Merges
This commit is contained in:
commit
bd150dfff9
7
.flake8
7
.flake8
|
@ -8,8 +8,11 @@ rst-roles = class,const,func,meth,mod,ref
|
|||
rst-directives = deprecated
|
||||
|
||||
per-file-ignores =
|
||||
# prefer naming tests descriptively rather than forcing comments
|
||||
spiffworkflow-backend/tests/*:S101,D103
|
||||
# asserts are ok in tests
|
||||
spiffworkflow-backend/tests/*:S101
|
||||
|
||||
# prefer naming functions descriptively rather than forcing comments
|
||||
spiffworkflow-backend/*:D103
|
||||
|
||||
spiffworkflow-backend/bin/keycloak_test_server.py:B950,D
|
||||
spiffworkflow-backend/conftest.py:S105
|
||||
|
|
|
@ -86,7 +86,7 @@ jobs:
|
|||
run: ./bin/wait_for_frontend_to_be_up 5
|
||||
- name: wait_for_keycloak
|
||||
working-directory: ./spiffworkflow-backend
|
||||
run: ./bin/wait_for_keycloak 5
|
||||
run: ./keycloak/bin/wait_for_keycloak 5
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@v4
|
||||
with:
|
||||
|
|
|
@ -712,7 +712,6 @@ class Task(object, metaclass=DeprecatedMetaTask):
|
|||
Defines the given attribute/value pairs.
|
||||
"""
|
||||
self.data.update(kwargs)
|
||||
data_log.info('Set data', extra=self.log_info())
|
||||
|
||||
def _inherit_data(self):
|
||||
"""
|
||||
|
|
|
@ -31,12 +31,6 @@ function get_python_dirs() {
|
|||
(git ls-tree -r HEAD --name-only | grep -E '\.py$' | awk -F '/' '{print $1}' | sort | uniq | grep -v '\.' | grep -Ev '^(bin|migrations)$') || echo ''
|
||||
}
|
||||
|
||||
function run_fix_docstrings() {
|
||||
if command -v fix_python_docstrings >/dev/null ; then
|
||||
fix_python_docstrings $(get_top_level_directories_containing_python_files)
|
||||
fi
|
||||
}
|
||||
|
||||
function run_autoflake() {
|
||||
# checking command -v autoflake8 is not good enough, since the asdf shim may be installed, which will make command -v succeed,
|
||||
# but autoflake8 may not have been pip installed inside the correct version of python.
|
||||
|
@ -86,7 +80,6 @@ done
|
|||
for python_project in "${python_projects[@]}" ; do
|
||||
if [[ "$subcommand" != "pre" ]] || [[ -n "$(git status --porcelain "$python_project")" ]]; then
|
||||
pushd "$python_project"
|
||||
run_fix_docstrings || run_fix_docstrings
|
||||
run_autoflake || run_autoflake
|
||||
popd
|
||||
fi
|
||||
|
|
|
@ -614,7 +614,7 @@ werkzeug = "*"
|
|||
type = "git"
|
||||
url = "https://github.com/sartography/flask-bpmn"
|
||||
reference = "main"
|
||||
resolved_reference = "c79c1e0b6d34ec05d82cce888b5e57b33d24403b"
|
||||
resolved_reference = "c18306300f4312b8d36e0197fd6b62399180d0b1"
|
||||
|
||||
[[package]]
|
||||
name = "flask-cors"
|
||||
|
@ -1760,7 +1760,7 @@ lxml = "*"
|
|||
type = "git"
|
||||
url = "https://github.com/sartography/SpiffWorkflow"
|
||||
reference = "main"
|
||||
resolved_reference = "80640024a8030481645f0c34f34c57e88f7b4f0c"
|
||||
resolved_reference = "1f51db962ccaed5810f5d0f7d76a932f056430ab"
|
||||
|
||||
[[package]]
|
||||
name = "sqlalchemy"
|
||||
|
|
|
@ -8,8 +8,11 @@ rst-roles = class,const,func,meth,mod,ref
|
|||
rst-directives = deprecated
|
||||
|
||||
per-file-ignores =
|
||||
# prefer naming tests descriptively rather than forcing comments
|
||||
tests/*:S101,D103
|
||||
# asserts are ok in tests
|
||||
tests/*:S101
|
||||
|
||||
# prefer naming functions descriptively rather than forcing comments
|
||||
*:D103
|
||||
|
||||
bin/keycloak_test_server.py:B950,D
|
||||
conftest.py:S105
|
||||
|
|
|
@ -22,8 +22,8 @@ set -o errtrace -o errexit -o nounset -o pipefail
|
|||
|
||||
# KEYCLOAK_BASE_URL=http://localhost:7002
|
||||
KEYCLOAK_BASE_URL=https://keycloak.dev.spiffworkflow.org
|
||||
# BACKEND_BASE_URL=http://localhost:7000
|
||||
BACKEND_BASE_URL=https://api.dev.spiffworkflow.org
|
||||
BACKEND_BASE_URL=http://localhost:7000
|
||||
# BACKEND_BASE_URL=https://api.dev.spiffworkflow.org
|
||||
REALM_NAME=spiffworkflow
|
||||
USERNAME=${1-fin}
|
||||
PASSWORD=${2-fin}
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"web": {
|
||||
"issuer": "http://localhost:8080/realms/finance",
|
||||
"auth_uri": "http://localhost:8080/realms/finance/protocol/openid-connect/auth",
|
||||
"client_id": "myclient",
|
||||
"client_secret": "OAh6rkjXIiPJDtPOz4459i3VtdlxGcce",
|
||||
"redirect_uris": ["http://localhost:5005/*"],
|
||||
"userinfo_uri": "http://localhost:8080/realms/finance/protocol/openid-connect/userinfo",
|
||||
"token_uri": "http://localhost:8080/realms/finance/protocol/openid-connect/token",
|
||||
"token_introspection_uri": "http://localhost:8080/realms/finance/protocol/openid-connect/token/introspect"
|
||||
}
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
# type: ignore
|
||||
"""keycloak_test_server."""
|
||||
# ./bin/start_keycloak # starts keycloak on 8080
|
||||
# pip install flask_oidc
|
||||
# pip install itsdangerous==2.0.1
|
||||
# python ./bin/keycloak_test_server.py # starts flask on 5005
|
||||
import json
|
||||
import logging
|
||||
|
||||
import requests
|
||||
from flask import Flask
|
||||
from flask import g
|
||||
from flask_oidc import OpenIDConnect
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.update(
|
||||
{
|
||||
"SECRET_KEY": "SomethingNotEntirelySecret",
|
||||
"TESTING": True,
|
||||
"DEBUG": True,
|
||||
"OIDC_CLIENT_SECRETS": "bin/keycloak_test_secrets.json",
|
||||
"OIDC_ID_TOKEN_COOKIE_SECURE": False,
|
||||
"OIDC_REQUIRE_VERIFIED_EMAIL": False,
|
||||
"OIDC_USER_INFO_ENABLED": True,
|
||||
"OIDC_OPENID_REALM": "flask-demo",
|
||||
"OIDC_SCOPES": ["openid", "email", "profile"],
|
||||
"OIDC_INTROSPECTION_AUTH_METHOD": "client_secret_post",
|
||||
}
|
||||
)
|
||||
|
||||
oidc = OpenIDConnect(app)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def hello_world():
|
||||
"""Hello_world."""
|
||||
if oidc.user_loggedin:
|
||||
return (
|
||||
'Hello, %s, <a href="/private">See private</a> '
|
||||
'<a href="/logout">Log out</a>'
|
||||
% oidc.user_getfield("preferred_username")
|
||||
)
|
||||
else:
|
||||
return 'Welcome anonymous, <a href="/private">Log in</a>'
|
||||
|
||||
|
||||
@app.route("/private")
|
||||
@oidc.require_login
|
||||
def hello_me():
|
||||
"""Example for protected endpoint that extracts private information from the OpenID Connect id_token.
|
||||
|
||||
Uses the accompanied access_token to access a backend service.
|
||||
"""
|
||||
info = oidc.user_getinfo(["preferred_username", "email", "sub"])
|
||||
|
||||
username = info.get("preferred_username")
|
||||
email = info.get("email")
|
||||
user_id = info.get("sub")
|
||||
|
||||
if user_id in oidc.credentials_store:
|
||||
try:
|
||||
from oauth2client.client import OAuth2Credentials
|
||||
|
||||
access_token = OAuth2Credentials.from_json(
|
||||
oidc.credentials_store[user_id]
|
||||
).access_token
|
||||
print("access_token=<%s>" % access_token)
|
||||
headers = {"Authorization": "Bearer %s" % (access_token)}
|
||||
# YOLO
|
||||
greeting = requests.get(
|
||||
"http://localhost:8080/greeting", headers=headers
|
||||
).text
|
||||
except BaseException:
|
||||
print("Could not access greeting-service")
|
||||
greeting = "Hello %s" % username
|
||||
|
||||
return """{} your email is {} and your user_id is {}!
|
||||
<ul>
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="//localhost:8080/auth/realms/finance/account?referrer=flask-app&referrer_uri=http://localhost:5005/private&">Account</a></li>
|
||||
</ul>""".format(
|
||||
greeting,
|
||||
email,
|
||||
user_id,
|
||||
)
|
||||
|
||||
|
||||
@app.route("/api", methods=["POST"])
|
||||
@oidc.accept_token(require_token=True, scopes_required=["openid"])
|
||||
def hello_api():
|
||||
"""OAuth 2.0 protected API endpoint accessible via AccessToken."""
|
||||
return json.dumps({"hello": "Welcome %s" % g.oidc_token_info["sub"]})
|
||||
|
||||
|
||||
@app.route("/logout")
|
||||
def logout():
|
||||
"""Performs local logout by removing the session cookie."""
|
||||
oidc.logout()
|
||||
return 'Hi, you have been logged out! <a href="/">Return</a>'
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(port=5005)
|
|
@ -29,7 +29,13 @@ else
|
|||
export FLASK_DEBUG=1
|
||||
|
||||
if [[ "${SPIFFWORKFLOW_BACKEND_RUN_DATA_SETUP:-}" != "false" ]]; then
|
||||
SPIFFWORKFLOW_BACKEND_FAIL_ON_INVALID_PROCESS_MODELS=false poetry run python bin/save_all_bpmn.py
|
||||
RUN_BACKGROUND_SCHEDULER=false SPIFFWORKFLOW_BACKEND_FAIL_ON_INVALID_PROCESS_MODELS=false poetry run python bin/save_all_bpmn.py
|
||||
fi
|
||||
FLASK_APP=src/spiffworkflow_backend poetry run flask run -p 7000
|
||||
|
||||
if [[ -z "${RUN_BACKGROUND_SCHEDULER:-}" ]]; then
|
||||
RUN_BACKGROUND_SCHEDULER=true
|
||||
fi
|
||||
|
||||
# this line blocks
|
||||
RUN_BACKGROUND_SCHEDULER="${RUN_BACKGROUND_SCHEDULER}" FLASK_APP=src/spiffworkflow_backend poetry run flask run -p 7000
|
||||
fi
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
function error_handler() {
|
||||
>&2 echo "Exited with BAD EXIT CODE '${2}' in ${0} script at line: ${1}."
|
||||
exit "$2"
|
||||
}
|
||||
trap 'error_handler ${LINENO} $?' ERR
|
||||
set -o errtrace -o errexit -o nounset -o pipefail
|
||||
|
||||
curl -v -F key1=value1 -F upload=@localfilename URL
|
|
@ -1,26 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
function error_handler() {
|
||||
>&2 echo "Exited with BAD EXIT CODE '${2}' in ${0} script at line: ${1}."
|
||||
exit "$2"
|
||||
}
|
||||
trap 'error_handler ${LINENO} $?' ERR
|
||||
set -o errtrace -o errexit -o nounset -o pipefail
|
||||
|
||||
if [[ "${1:-}" == "c" ]]; then
|
||||
curl --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d '{}'
|
||||
elif grep -qE '^[0-9]$' <<<"${1:-}" ; then
|
||||
curl --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d "{ \"task_identifier\": \"${1}\"}"
|
||||
else
|
||||
./bin/recreate_db clean
|
||||
curl --silent --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d '{ "task_identifier": "1", "answer": {"Product Name": "G", "Quantity": "2"}}' | jq .
|
||||
curl --silent --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d '{ "task_identifier": "1", "answer": {"Sleeve Type": "Short"}}' | jq .
|
||||
curl --silent --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d '{ "task_identifier": "1", "answer": {"Continue shopping?": "N"}}' | jq .
|
||||
curl --silent --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d '{ "task_identifier": "1", "answer": {"Shipping Method": "Overnight"}}' | jq .
|
||||
curl --silent --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d '{ "task_identifier": "1", "answer": {"Shipping Address": "Somewhere"}}' | jq .
|
||||
curl --silent --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d '{ "task_identifier": "1", "answer": {"Place Order": "Y"}}' | jq .
|
||||
curl --silent --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d '{ "task_identifier": "1", "answer": {"Card Number": "MY_CARD"}}' | jq .
|
||||
curl --silent --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d '{ "task_identifier": "2", "answer": {"Was the customer charged?": "Y"}}' | jq .
|
||||
curl --silent --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d '{ "task_identifier": "1", "answer": {"Was the product available?": "Y"}}' | jq .
|
||||
curl --silent --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d '{ "task_identifier": "1", "answer": {"Was the order shipped?": "Y"}}' | jq .
|
||||
fi
|
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
function error_handler() {
|
||||
>&2 echo "Exited with BAD EXIT CODE '${2}' in ${0} script at line: ${1}."
|
||||
exit "$2"
|
||||
}
|
||||
trap 'error_handler ${LINENO} $?' ERR
|
||||
set -o errtrace -o errexit -o nounset -o pipefail
|
||||
|
||||
user_file_with_one_email_per_line="${1:-}"
|
||||
if [[ -z "${1:-}" ]]; then
|
||||
>&2 echo "usage: $(basename "$0") [user_file_with_one_email_per_line]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
KEYCLOAK_BASE_URL=http://localhost:7002
|
||||
REALM_NAME=master
|
||||
ADMIN_USERNAME="admin"
|
||||
ADMIN_PASSWORD="admin"
|
||||
SECURE=false
|
||||
|
||||
KEYCLOAK_URL=$KEYCLOAK_BASE_URL/realms/$REALM_NAME/protocol/openid-connect/token
|
||||
|
||||
if [[ $SECURE = 'y' ]]; then
|
||||
INSECURE=
|
||||
else
|
||||
INSECURE=--insecure
|
||||
fi
|
||||
|
||||
# https://www.appsdeveloperblog.com/keycloak-rest-api-create-a-new-user/
|
||||
result=$(curl --fail -s -X POST "$KEYCLOAK_URL" "$INSECURE" \
|
||||
--header 'Content-Type: application/x-www-form-urlencoded' \
|
||||
--data-urlencode "username=${ADMIN_USERNAME}" \
|
||||
--data-urlencode "password=${ADMIN_PASSWORD}" \
|
||||
--data-urlencode 'grant_type=password' \
|
||||
--data-urlencode 'client_id=admin-cli'
|
||||
)
|
||||
backend_token=$(jq -r '.access_token' <<< "$result")
|
||||
|
||||
while read -r user_email; do
|
||||
if [[ -n "$user_email" ]]; then
|
||||
username=$(awk -F '@' '{print $1}' <<<"$user_email")
|
||||
credentials='{"type":"password","value":"'"${username}"'","temporary":false}'
|
||||
|
||||
curl --fail --location --request POST 'http://localhost:7002/admin/realms/spiffworkflow/users' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H "Authorization: Bearer $backend_token" \
|
||||
--data-raw '{"email":"'"${user_email}"'", "enabled":"true", "username":"'"${username}"'", "credentials":['"${credentials}"']}'
|
||||
fi
|
||||
done <"$user_file_with_one_email_per_line"
|
|
@ -7,6 +7,8 @@ function error_handler() {
|
|||
trap 'error_handler ${LINENO} $?' ERR
|
||||
set -o errtrace -o errexit -o nounset -o pipefail
|
||||
|
||||
script_dir="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
|
||||
|
||||
realms="$*"
|
||||
if [[ -z "$realms" ]]; then
|
||||
realms="spiffworkflow-realm"
|
||||
|
@ -19,7 +21,7 @@ docker exec keycloak /opt/keycloak/bin/kc.sh export --dir "${docker_container_pa
|
|||
docker cp "keycloak:${docker_container_path}" "$local_tmp_dir"
|
||||
|
||||
for realm in $realms ; do
|
||||
cp "${local_tmp_dir}/hey/${realm}.json" bin/
|
||||
cp "${local_tmp_dir}/hey/${realm}.json" "${script_dir}/../realm_exports/"
|
||||
done
|
||||
|
||||
rm -rf "$local_tmp_dir"
|
|
@ -45,7 +45,7 @@ docker run \
|
|||
-Dkeycloak.profile.feature.admin_fine_grained_authz=enabled
|
||||
|
||||
script_dir="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
|
||||
cp "${script_dir}/spiffworkflow-realm.json" /tmp/spiffworkflow-realm.json
|
||||
cp "${script_dir}/../realm_exports/spiffworkflow-realm.json" /tmp/spiffworkflow-realm.json
|
||||
spiff_subdomain="unused-for-local-dev"
|
||||
perl -pi -e "s/{{SPIFF_SUBDOMAIN}}/${spiff_subdomain}/g" /tmp/spiffworkflow-realm.json
|
||||
docker cp /tmp/spiffworkflow-realm.json keycloak:/tmp
|
|
@ -634,6 +634,46 @@
|
|||
"realmRoles" : [ "default-roles-spiffworkflow" ],
|
||||
"notBefore" : 0,
|
||||
"groups" : [ ]
|
||||
}, {
|
||||
"id" : "29ba295e-9a70-41f1-bf0d-f02b468397c5",
|
||||
"createdTimestamp" : 1674148694595,
|
||||
"username" : "finance.lead",
|
||||
"enabled" : true,
|
||||
"totp" : false,
|
||||
"emailVerified" : false,
|
||||
"email" : "finance.lead@status.im",
|
||||
"credentials" : [ {
|
||||
"id" : "8f746fde-0a10-41b4-a973-0b967de73839",
|
||||
"type" : "password",
|
||||
"createdDate" : 1674148694661,
|
||||
"secretData" : "{\"value\":\"vhe8ONTdkYaXLcSr73/4Ey//7U7rxh/0hiGc9S0wp8FV3EUsf+3bQSreDQCTp3DePJInpVCV34d4T0Ij+6Po0A==\",\"salt\":\"s6hEEdUPlULWfqGpxlG+TQ==\",\"additionalParameters\":{}}",
|
||||
"credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}"
|
||||
} ],
|
||||
"disableableCredentialTypes" : [ ],
|
||||
"requiredActions" : [ ],
|
||||
"realmRoles" : [ "default-roles-spiffworkflow" ],
|
||||
"notBefore" : 0,
|
||||
"groups" : [ ]
|
||||
}, {
|
||||
"id" : "f6d2488a-446c-493b-bbe8-210ede6f3e42",
|
||||
"createdTimestamp" : 1674148694899,
|
||||
"username" : "finance.sme",
|
||||
"enabled" : true,
|
||||
"totp" : false,
|
||||
"emailVerified" : false,
|
||||
"email" : "finance.sme@status.im",
|
||||
"credentials" : [ {
|
||||
"id" : "faee8eaa-0bf4-4050-8d17-8b6b52f0b7ee",
|
||||
"type" : "password",
|
||||
"createdDate" : 1674148694945,
|
||||
"secretData" : "{\"value\":\"tk78HqSoRT0PAJ45zt2/q6gXRYxvDDIYtLzsVdYM3sHk+tRkgYeXoyKDSyRwHm9AjbM8jFI5yUXPsWck8vemOg==\",\"salt\":\"aR9qgYMx1VUfOrppTDzMmQ==\",\"additionalParameters\":{}}",
|
||||
"credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}"
|
||||
} ],
|
||||
"disableableCredentialTypes" : [ ],
|
||||
"requiredActions" : [ ],
|
||||
"realmRoles" : [ "default-roles-spiffworkflow" ],
|
||||
"notBefore" : 0,
|
||||
"groups" : [ ]
|
||||
}, {
|
||||
"id" : "9b46f3be-a81d-4b76-92e6-2ac8462f5ec8",
|
||||
"createdTimestamp" : 1665688255982,
|
||||
|
@ -674,6 +714,26 @@
|
|||
"realmRoles" : [ "default-roles-spiffworkflow" ],
|
||||
"notBefore" : 0,
|
||||
"groups" : [ ]
|
||||
}, {
|
||||
"id" : "f55135de-7341-459d-8a42-a59f52d05bed",
|
||||
"createdTimestamp" : 1674148694958,
|
||||
"username" : "infra.sme",
|
||||
"enabled" : true,
|
||||
"totp" : false,
|
||||
"emailVerified" : false,
|
||||
"email" : "infra.sme@status.im",
|
||||
"credentials" : [ {
|
||||
"id" : "e1f4368c-ed7c-481c-9426-fc0b8f2bf520",
|
||||
"type" : "password",
|
||||
"createdDate" : 1674148695008,
|
||||
"secretData" : "{\"value\":\"7RHwvrhGAA3EddNNjPaVah+EOg5be0eugiwLLQLGlhFGSdGfg6kiUmPr5wBqBabivXHiSZgv/BiaL5KQ/VmR+A==\",\"salt\":\"HW3yCxErwpKASPvHX8o9Uw==\",\"additionalParameters\":{}}",
|
||||
"credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}"
|
||||
} ],
|
||||
"disableableCredentialTypes" : [ ],
|
||||
"requiredActions" : [ ],
|
||||
"realmRoles" : [ "default-roles-spiffworkflow" ],
|
||||
"notBefore" : 0,
|
||||
"groups" : [ ]
|
||||
}, {
|
||||
"id" : "1561518b-c327-491e-9db3-23c2b5394104",
|
||||
"createdTimestamp" : 1669303773974,
|
||||
|
@ -843,6 +903,46 @@
|
|||
"realmRoles" : [ "default-roles-spiffworkflow" ],
|
||||
"notBefore" : 0,
|
||||
"groups" : [ ]
|
||||
}, {
|
||||
"id" : "530e99cb-b400-4baf-8ca6-22e64a30ef84",
|
||||
"createdTimestamp" : 1674148694688,
|
||||
"username" : "legal.lead",
|
||||
"enabled" : true,
|
||||
"totp" : false,
|
||||
"emailVerified" : false,
|
||||
"email" : "legal.lead@status.im",
|
||||
"credentials" : [ {
|
||||
"id" : "81f3aeca-8316-4a1b-8eb9-2570c062d0df",
|
||||
"type" : "password",
|
||||
"createdDate" : 1674148694733,
|
||||
"secretData" : "{\"value\":\"puCrVcCNrO6P0VF8w0ZSx97RHi/c6NCuSeTidk/tEfSpZyY9x0oz/bkdFJO359HuvhN5HMBQ+CKPNbW1VjOSoA==\",\"salt\":\"ZczpeV+0QJGZG96EfLWYRQ==\",\"additionalParameters\":{}}",
|
||||
"credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}"
|
||||
} ],
|
||||
"disableableCredentialTypes" : [ ],
|
||||
"requiredActions" : [ ],
|
||||
"realmRoles" : [ "default-roles-spiffworkflow" ],
|
||||
"notBefore" : 0,
|
||||
"groups" : [ ]
|
||||
}, {
|
||||
"id" : "2a3176a0-8dd5-4223-a3e1-3cac4134e474",
|
||||
"createdTimestamp" : 1674148695030,
|
||||
"username" : "legal.sme",
|
||||
"enabled" : true,
|
||||
"totp" : false,
|
||||
"emailVerified" : false,
|
||||
"email" : "legal.sme@status.im",
|
||||
"credentials" : [ {
|
||||
"id" : "52fd8bd4-8fc4-4b71-8325-424220ef83af",
|
||||
"type" : "password",
|
||||
"createdDate" : 1674148695076,
|
||||
"secretData" : "{\"value\":\"Rce1M5ph1ITsCguiHlv7YMcDTyofRnSPnOraQskkmeojV+tlUeBBsHV1fTiqJ4f13vE1qtnwC/60vQV8BprsHw==\",\"salt\":\"zFyJq5G2F/pZeLmgKaGoxQ==\",\"additionalParameters\":{}}",
|
||||
"credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}"
|
||||
} ],
|
||||
"disableableCredentialTypes" : [ ],
|
||||
"requiredActions" : [ ],
|
||||
"realmRoles" : [ "default-roles-spiffworkflow" ],
|
||||
"notBefore" : 0,
|
||||
"groups" : [ ]
|
||||
}, {
|
||||
"id" : "6f5bfa09-7494-4a2f-b871-cf327048cac7",
|
||||
"createdTimestamp" : 1665517010600,
|
||||
|
@ -905,6 +1005,26 @@
|
|||
"realmRoles" : [ "default-roles-spiffworkflow" ],
|
||||
"notBefore" : 0,
|
||||
"groups" : [ ]
|
||||
}, {
|
||||
"id" : "c3ea06ee-c497-48e6-8816-43c8ef68bd8b",
|
||||
"createdTimestamp" : 1674148694747,
|
||||
"username" : "program.lead",
|
||||
"enabled" : true,
|
||||
"totp" : false,
|
||||
"emailVerified" : false,
|
||||
"email" : "program.lead@status.im",
|
||||
"credentials" : [ {
|
||||
"id" : "393e3cd9-c403-41dd-8562-7edba6acedd3",
|
||||
"type" : "password",
|
||||
"createdDate" : 1674148694793,
|
||||
"secretData" : "{\"value\":\"AD/rFDJcnQNVSZLVnLl6FzdiMSkRFiKiF2L6jyPtnAOAuQ6IivNvDIqiZf98rPuSq1zs8wjeDzFzyXvTYp7Pjg==\",\"salt\":\"T4XlF58M6LNTX8ksxYq8jQ==\",\"additionalParameters\":{}}",
|
||||
"credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}"
|
||||
} ],
|
||||
"disableableCredentialTypes" : [ ],
|
||||
"requiredActions" : [ ],
|
||||
"realmRoles" : [ "default-roles-spiffworkflow" ],
|
||||
"notBefore" : 0,
|
||||
"groups" : [ ]
|
||||
}, {
|
||||
"id" : "f3852a7d-8adf-494f-b39d-96ad4c899ee5",
|
||||
"createdTimestamp" : 1665516926300,
|
||||
|
@ -925,6 +1045,26 @@
|
|||
"realmRoles" : [ "default-roles-spiffworkflow" ],
|
||||
"notBefore" : 0,
|
||||
"groups" : [ ]
|
||||
}, {
|
||||
"id" : "74374cda-1516-48e5-9ef2-1fd7bcee84d3",
|
||||
"createdTimestamp" : 1674148695088,
|
||||
"username" : "security.sme",
|
||||
"enabled" : true,
|
||||
"totp" : false,
|
||||
"emailVerified" : false,
|
||||
"email" : "security.sme@status.im",
|
||||
"credentials" : [ {
|
||||
"id" : "43427e80-292e-453f-9968-511a1064729e",
|
||||
"type" : "password",
|
||||
"createdDate" : 1674148695133,
|
||||
"secretData" : "{\"value\":\"HB68S1rm/fef2nY2qpakAyZ0a+OFM0G/Xp+kHNdTQSWZA6fYq8EUzhfTFkUQ5xuTriOesXao0srtFmcCs2Pi8Q==\",\"salt\":\"e8J1O8M7mrDq/jTJXzwYyQ==\",\"additionalParameters\":{}}",
|
||||
"credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}"
|
||||
} ],
|
||||
"disableableCredentialTypes" : [ ],
|
||||
"requiredActions" : [ ],
|
||||
"realmRoles" : [ "default-roles-spiffworkflow" ],
|
||||
"notBefore" : 0,
|
||||
"groups" : [ ]
|
||||
}, {
|
||||
"id" : "487d3a85-89dd-4839-957a-c3f6d70551f6",
|
||||
"createdTimestamp" : 1657115173081,
|
||||
|
@ -961,6 +1101,26 @@
|
|||
},
|
||||
"notBefore" : 0,
|
||||
"groups" : [ ]
|
||||
}, {
|
||||
"id" : "3d45bb85-0a2d-4b15-8a19-d26a5619d359",
|
||||
"createdTimestamp" : 1674148694810,
|
||||
"username" : "services.lead",
|
||||
"enabled" : true,
|
||||
"totp" : false,
|
||||
"emailVerified" : false,
|
||||
"email" : "services.lead@status.im",
|
||||
"credentials" : [ {
|
||||
"id" : "45607c53-3768-4f76-bda3-4d31b39ffccd",
|
||||
"type" : "password",
|
||||
"createdDate" : 1674148694884,
|
||||
"secretData" : "{\"value\":\"E3GPcOLU56efhBQE7MMZa0OM0FAtgK5kDA9sy65uCwSyaoZGp4ZVUDsIfIkWe+TEEQA5QP5FVJbJhwvdkx3m9w==\",\"salt\":\"dySpiEZxeyb11oQZR2WYVQ==\",\"additionalParameters\":{}}",
|
||||
"credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}"
|
||||
} ],
|
||||
"disableableCredentialTypes" : [ ],
|
||||
"requiredActions" : [ ],
|
||||
"realmRoles" : [ "default-roles-spiffworkflow" ],
|
||||
"notBefore" : 0,
|
||||
"groups" : [ ]
|
||||
} ],
|
||||
"scopeMappings" : [ {
|
||||
"clientScope" : "offline_access",
|
||||
|
@ -2174,7 +2334,7 @@
|
|||
"subType" : "authenticated",
|
||||
"subComponents" : { },
|
||||
"config" : {
|
||||
"allowed-protocol-mapper-types" : [ "saml-user-property-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper" ]
|
||||
"allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper" ]
|
||||
}
|
||||
}, {
|
||||
"id" : "d68e938d-dde6-47d9-bdc8-8e8523eb08cd",
|
||||
|
@ -2192,7 +2352,7 @@
|
|||
"subType" : "anonymous",
|
||||
"subComponents" : { },
|
||||
"config" : {
|
||||
"allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-attribute-mapper" ]
|
||||
"allowed-protocol-mapper-types" : [ "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-attribute-mapper" ]
|
||||
}
|
||||
}, {
|
||||
"id" : "3854361d-3fe5-47fb-9417-a99592e3dc5c",
|
||||
|
@ -2282,7 +2442,7 @@
|
|||
"internationalizationEnabled" : false,
|
||||
"supportedLocales" : [ ],
|
||||
"authenticationFlows" : [ {
|
||||
"id" : "76ae522e-7ab3-48dc-af76-9cb8069368a2",
|
||||
"id" : "fd44ea2b-052b-470a-9afd-216390c40d54",
|
||||
"alias" : "Account verification options",
|
||||
"description" : "Method with which to verity the existing account",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2304,7 +2464,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "ddf80243-ec40-4c21-ae94-2967d841f84c",
|
||||
"id" : "88a96abb-a839-4405-97bf-fa53f5290482",
|
||||
"alias" : "Authentication Options",
|
||||
"description" : "Authentication options.",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2333,7 +2493,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "4f075680-46b7-49eb-b94c-d7425f105cb9",
|
||||
"id" : "cbe05604-280f-4304-bda5-ed5245537f4d",
|
||||
"alias" : "Browser - Conditional OTP",
|
||||
"description" : "Flow to determine if the OTP is required for the authentication",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2355,7 +2515,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "a0467c77-c3dc-4df6-acd2-c05ca13601ed",
|
||||
"id" : "5275913f-e597-4a89-b416-4f9412b9082b",
|
||||
"alias" : "Direct Grant - Conditional OTP",
|
||||
"description" : "Flow to determine if the OTP is required for the authentication",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2377,7 +2537,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "07536fec-8d41-4c73-845f-ca85002022e0",
|
||||
"id" : "a0afd432-ed89-41c6-be8d-f31834e80ba1",
|
||||
"alias" : "First broker login - Conditional OTP",
|
||||
"description" : "Flow to determine if the OTP is required for the authentication",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2399,7 +2559,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "f123f912-71fb-4596-97f9-c0628a59413d",
|
||||
"id" : "fab45b23-3353-4482-b690-07f3ab177776",
|
||||
"alias" : "Handle Existing Account",
|
||||
"description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2421,7 +2581,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "03c26cc5-366b-462d-9297-b4016f8d7c57",
|
||||
"id" : "f5eb0757-f2cd-4d4b-9608-d1b9ae4fd941",
|
||||
"alias" : "Reset - Conditional OTP",
|
||||
"description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2443,7 +2603,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "1b4f474e-aa64-45cc-90f1-63504585d89c",
|
||||
"id" : "521586b9-ade0-4f8c-aff6-3d6c357aa6e4",
|
||||
"alias" : "User creation or linking",
|
||||
"description" : "Flow for the existing/non-existing user alternatives",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2466,7 +2626,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "38024dd6-daff-45de-8782-06b07b7bfa56",
|
||||
"id" : "b21bb98a-9241-4484-966b-6f8294ba2186",
|
||||
"alias" : "Verify Existing Account by Re-authentication",
|
||||
"description" : "Reauthentication of existing account",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2488,7 +2648,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "b7e30fca-e4ac-4886-a2e7-642fe2a27ee7",
|
||||
"id" : "7ec2a1f6-37e7-444e-9376-dee7d442ec2f",
|
||||
"alias" : "browser",
|
||||
"description" : "browser based authentication",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2524,7 +2684,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "92e3571d-ac3e-4e79-a391-5315954e866f",
|
||||
"id" : "1bc2b251-bf69-40b1-ace2-e3be5037b910",
|
||||
"alias" : "clients",
|
||||
"description" : "Base authentication for clients",
|
||||
"providerId" : "client-flow",
|
||||
|
@ -2560,7 +2720,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "5093dd2d-fe5d-4f41-a54d-03cd648d9b7f",
|
||||
"id" : "12a854bd-4d8a-49eb-8be5-cfc9d25cba54",
|
||||
"alias" : "direct grant",
|
||||
"description" : "OpenID Connect Resource Owner Grant",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2589,7 +2749,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "95d2f1ff-6907-47ce-a93c-db462fe04844",
|
||||
"id" : "99ebf3a7-674e-4603-a0cf-8fe4c6dd4cfc",
|
||||
"alias" : "docker auth",
|
||||
"description" : "Used by Docker clients to authenticate against the IDP",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2604,7 +2764,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "27405ee8-5730-419c-944c-a7c67edd91ce",
|
||||
"id" : "a241b9b8-9c21-4a47-877a-5a6535678c90",
|
||||
"alias" : "first broker login",
|
||||
"description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2627,7 +2787,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "fce6d926-3a99-40ee-b79e-cae84493dbd8",
|
||||
"id" : "c9df7ad1-9b59-46ec-a85e-714fd682569c",
|
||||
"alias" : "forms",
|
||||
"description" : "Username, password, otp and other auth forms.",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2649,7 +2809,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "75d93596-b7fb-4a2c-a780-e6a038e66fe9",
|
||||
"id" : "14f21f85-2bcb-4ed6-aaab-1ee237da153f",
|
||||
"alias" : "http challenge",
|
||||
"description" : "An authentication flow based on challenge-response HTTP Authentication Schemes",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2671,7 +2831,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "04cdc1ac-c58d-4f8c-bc10-7d5e2bb99485",
|
||||
"id" : "bc7e40c0-9172-496b-8db1-3ebc20065887",
|
||||
"alias" : "registration",
|
||||
"description" : "registration flow",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2687,7 +2847,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "99593c1e-f2a5-4198-ad41-634694259110",
|
||||
"id" : "ef97f42b-7f32-442c-ab4a-8cb6c873cf1f",
|
||||
"alias" : "registration form",
|
||||
"description" : "registration form",
|
||||
"providerId" : "form-flow",
|
||||
|
@ -2723,7 +2883,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "7d53f026-b05e-4a9c-aba6-23b17826a4d4",
|
||||
"id" : "1ee2b484-3836-466f-9f5b-bbf47abc5ad7",
|
||||
"alias" : "reset credentials",
|
||||
"description" : "Reset credentials for a user if they forgot their password or something",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2759,7 +2919,7 @@
|
|||
"userSetupAllowed" : false
|
||||
} ]
|
||||
}, {
|
||||
"id" : "7ca17e64-f916-4d6c-91f0-815ec66f50e8",
|
||||
"id" : "4918f32e-6780-4ddd-a1a2-c3ae9d8fa598",
|
||||
"alias" : "saml ecp",
|
||||
"description" : "SAML ECP Profile Authentication Flow",
|
||||
"providerId" : "basic-flow",
|
||||
|
@ -2775,13 +2935,13 @@
|
|||
} ]
|
||||
} ],
|
||||
"authenticatorConfig" : [ {
|
||||
"id" : "9b71d817-b999-479d-97f8-07e39dd9e9fa",
|
||||
"id" : "5479944f-6198-48df-8a18-4bc0caba5963",
|
||||
"alias" : "create unique user config",
|
||||
"config" : {
|
||||
"require.password.update.after.registration" : "false"
|
||||
}
|
||||
}, {
|
||||
"id" : "f9f13ba1-6a17-436b-a80b-6ccc042f9fc2",
|
||||
"id" : "fd9f571f-0d6e-4ece-a3e5-fffccc1e4fad",
|
||||
"alias" : "review profile config",
|
||||
"config" : {
|
||||
"update.profile.on.first.login" : "missing"
|
||||
|
@ -2876,4 +3036,4 @@
|
|||
"clientPolicies" : {
|
||||
"policies" : [ ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
finance.lead@status.im
|
||||
legal.lead@status.im
|
||||
program.lead@status.im
|
||||
services.lead@status.im
|
||||
finance.sme@status.im
|
||||
infra.sme@status.im
|
||||
legal.sme@status.im
|
||||
security.sme@status.im
|
||||
|
|
@ -248,7 +248,7 @@ zstd = ["zstandard"]
|
|||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2022.9.24"
|
||||
version = "2022.12.7"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
category = "main"
|
||||
optional = false
|
||||
|
@ -610,6 +610,37 @@ python-versions = "*"
|
|||
bcrypt = ">=3.1.1"
|
||||
Flask = "*"
|
||||
|
||||
[[package]]
|
||||
name = "flask-bpmn"
|
||||
version = "0.0.0"
|
||||
description = "Flask Bpmn"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "^3.7"
|
||||
develop = false
|
||||
|
||||
[package.dependencies]
|
||||
click = "^8.0.1"
|
||||
flask = "*"
|
||||
flask-admin = "*"
|
||||
flask-bcrypt = "*"
|
||||
flask-cors = "*"
|
||||
flask-mail = "*"
|
||||
flask-marshmallow = "*"
|
||||
flask-migrate = "*"
|
||||
flask-restful = "*"
|
||||
greenlet = "^2.0.1"
|
||||
sentry-sdk = "*"
|
||||
sphinx-autoapi = "^2.0.0"
|
||||
spiffworkflow = "*"
|
||||
werkzeug = "*"
|
||||
|
||||
[package.source]
|
||||
type = "git"
|
||||
url = "https://github.com/sartography/flask-bpmn"
|
||||
reference = "main"
|
||||
resolved_reference = "c18306300f4312b8d36e0197fd6b62399180d0b1"
|
||||
|
||||
[[package]]
|
||||
name = "Flask-Cors"
|
||||
version = "3.0.10"
|
||||
|
@ -1043,19 +1074,19 @@ python-versions = "*"
|
|||
|
||||
[[package]]
|
||||
name = "mysql-connector-python"
|
||||
version = "8.0.31"
|
||||
version = "8.0.32"
|
||||
description = "MySQL driver written in Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
protobuf = ">=3.11.0,<=3.20.1"
|
||||
protobuf = ">=3.11.0,<=3.20.3"
|
||||
|
||||
[package.extras]
|
||||
compression = ["lz4 (>=2.1.6,<=3.1.3)", "zstandard (>=0.12.0,<=0.15.2)"]
|
||||
compression = ["lz4 (>=2.1.6,<=3.1.3)", "zstandard (>=0.12.0,<=0.19.0)"]
|
||||
dns-srv = ["dnspython (>=1.16.0,<=2.1.0)"]
|
||||
gssapi = ["gssapi (>=1.6.9,<=1.8.1)"]
|
||||
gssapi = ["gssapi (>=1.6.9,<=1.8.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "nodeenv"
|
||||
|
@ -1179,7 +1210,7 @@ wcwidth = "*"
|
|||
|
||||
[[package]]
|
||||
name = "protobuf"
|
||||
version = "3.20.1"
|
||||
version = "3.20.3"
|
||||
description = "Protocol Buffers"
|
||||
category = "main"
|
||||
optional = false
|
||||
|
@ -1745,7 +1776,7 @@ description = "A workflow framework and BPMN/DMN Processor"
|
|||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
develop = true
|
||||
develop = false
|
||||
|
||||
[package.dependencies]
|
||||
celery = "*"
|
||||
|
@ -1753,8 +1784,10 @@ configparser = "*"
|
|||
lxml = "*"
|
||||
|
||||
[package.source]
|
||||
type = "directory"
|
||||
url = "../../SpiffWorkflow"
|
||||
type = "git"
|
||||
url = "https://github.com/sartography/SpiffWorkflow"
|
||||
reference = "be26100bcbef8026e26312c665dae42faf476485"
|
||||
resolved_reference = "be26100bcbef8026e26312c665dae42faf476485"
|
||||
|
||||
[[package]]
|
||||
name = "SQLAlchemy"
|
||||
|
@ -2125,7 +2158,7 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools"
|
|||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = ">=3.9,<3.12"
|
||||
content-hash = "f646836512a18f2a0e9ba4979926e004abd17790da5178e06e87092fdf23c35f"
|
||||
content-hash = "d804b8cbb34882f92cf19e5e59231aa7eac84764298fe7eae72bd03112e09496"
|
||||
|
||||
[metadata.files]
|
||||
alabaster = [
|
||||
|
@ -2227,8 +2260,8 @@ celery = [
|
|||
{file = "celery-5.2.7.tar.gz", hash = "sha256:fafbd82934d30f8a004f81e8f7a062e31413a23d444be8ee3326553915958c6d"},
|
||||
]
|
||||
certifi = [
|
||||
{file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"},
|
||||
{file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"},
|
||||
{file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"},
|
||||
{file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
|
||||
]
|
||||
cfgv = [
|
||||
{file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
|
||||
|
@ -2388,6 +2421,7 @@ Flask-Bcrypt = [
|
|||
{file = "Flask-Bcrypt-1.0.1.tar.gz", hash = "sha256:f07b66b811417ea64eb188ae6455b0b708a793d966e1a80ceec4a23bc42a4369"},
|
||||
{file = "Flask_Bcrypt-1.0.1-py3-none-any.whl", hash = "sha256:062fd991dc9118d05ac0583675507b9fe4670e44416c97e0e6819d03d01f808a"},
|
||||
]
|
||||
flask-bpmn = []
|
||||
Flask-Cors = [
|
||||
{file = "Flask-Cors-3.0.10.tar.gz", hash = "sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de"},
|
||||
{file = "Flask_Cors-3.0.10-py2.py3-none-any.whl", hash = "sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438"},
|
||||
|
@ -2465,7 +2499,6 @@ greenlet = [
|
|||
{file = "greenlet-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5b0ff9878333823226d270417f24f4d06f235cb3e54d1103b71ea537a6a86ce"},
|
||||
{file = "greenlet-2.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be9e0fb2ada7e5124f5282d6381903183ecc73ea019568d6d63d33f25b2a9000"},
|
||||
{file = "greenlet-2.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b493db84d124805865adc587532ebad30efa68f79ad68f11b336e0a51ec86c2"},
|
||||
{file = "greenlet-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0459d94f73265744fee4c2d5ec44c6f34aa8a31017e6e9de770f7bcf29710be9"},
|
||||
{file = "greenlet-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a20d33124935d27b80e6fdacbd34205732660e0a1d35d8b10b3328179a2b51a1"},
|
||||
{file = "greenlet-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:ea688d11707d30e212e0110a1aac7f7f3f542a259235d396f88be68b649e47d1"},
|
||||
{file = "greenlet-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:afe07421c969e259e9403c3bb658968702bc3b78ec0b6fde3ae1e73440529c23"},
|
||||
|
@ -2474,7 +2507,6 @@ greenlet = [
|
|||
{file = "greenlet-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:659f167f419a4609bc0516fb18ea69ed39dbb25594934bd2dd4d0401660e8a1e"},
|
||||
{file = "greenlet-2.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:356e4519d4dfa766d50ecc498544b44c0249b6de66426041d7f8b751de4d6b48"},
|
||||
{file = "greenlet-2.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:811e1d37d60b47cb8126e0a929b58c046251f28117cb16fcd371eed61f66b764"},
|
||||
{file = "greenlet-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d38ffd0e81ba8ef347d2be0772e899c289b59ff150ebbbbe05dc61b1246eb4e0"},
|
||||
{file = "greenlet-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0109af1138afbfb8ae647e31a2b1ab030f58b21dd8528c27beaeb0093b7938a9"},
|
||||
{file = "greenlet-2.0.1-cp38-cp38-win32.whl", hash = "sha256:88c8d517e78acdf7df8a2134a3c4b964415b575d2840a2746ddb1cc6175f8608"},
|
||||
{file = "greenlet-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:d6ee1aa7ab36475035eb48c01efae87d37936a8173fc4d7b10bb02c2d75dd8f6"},
|
||||
|
@ -2483,7 +2515,6 @@ greenlet = [
|
|||
{file = "greenlet-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:505138d4fa69462447a562a7c2ef723c6025ba12ac04478bc1ce2fcc279a2db5"},
|
||||
{file = "greenlet-2.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cce1e90dd302f45716a7715517c6aa0468af0bf38e814ad4eab58e88fc09f7f7"},
|
||||
{file = "greenlet-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e9744c657d896c7b580455e739899e492a4a452e2dd4d2b3e459f6b244a638d"},
|
||||
{file = "greenlet-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:662e8f7cad915ba75d8017b3e601afc01ef20deeeabf281bd00369de196d7726"},
|
||||
{file = "greenlet-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:41b825d65f31e394b523c84db84f9383a2f7eefc13d987f308f4663794d2687e"},
|
||||
{file = "greenlet-2.0.1-cp39-cp39-win32.whl", hash = "sha256:db38f80540083ea33bdab614a9d28bcec4b54daa5aff1668d7827a9fc769ae0a"},
|
||||
{file = "greenlet-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b23d2a46d53210b498e5b701a1913697671988f4bf8e10f935433f6e7c332fb6"},
|
||||
|
@ -2740,32 +2771,31 @@ mypy-extensions = [
|
|||
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
|
||||
]
|
||||
mysql-connector-python = [
|
||||
{file = "mysql-connector-python-8.0.31.tar.gz", hash = "sha256:0fbe8f5441ad781b4f65c54a10ac77c6a329591456607e042786528599519636"},
|
||||
{file = "mysql_connector_python-8.0.31-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3e271d8de00d5e9f9bd4b212c8e23d2986dead0f20379010f3b274a3e24cbfcb"},
|
||||
{file = "mysql_connector_python-8.0.31-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:f3ee04a601f9cb90ace9618bbe2fa8e5bb59be3eb0c2bd8a5405fe69e05e446b"},
|
||||
{file = "mysql_connector_python-8.0.31-cp310-cp310-manylinux1_i686.whl", hash = "sha256:f89b7a731885b8a04248e4d8d124705ca836f0ddd3b7cf0c789e21f4b32810ed"},
|
||||
{file = "mysql_connector_python-8.0.31-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:48eb34f4e69a2fba56f310de6682862a15d46cd2bd51ee6eebc3a244e4ee0aa6"},
|
||||
{file = "mysql_connector_python-8.0.31-cp310-cp310-win_amd64.whl", hash = "sha256:a570a72e0015b36b9c0775ae27c1d4946225f02f62129d16a14e9d77a38c0717"},
|
||||
{file = "mysql_connector_python-8.0.31-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a7ac859a52486ac319e37f61469bbb9023faef38018223efa74e953f1fe23d36"},
|
||||
{file = "mysql_connector_python-8.0.31-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:79d6a6e8ce955df5ca0786cb8ed8fbd999745c9b50def89993a2a0f4732de721"},
|
||||
{file = "mysql_connector_python-8.0.31-cp311-cp311-manylinux1_i686.whl", hash = "sha256:e60426af313dcd526028d018d70757a82c5cc0673776b2a614e2180b5970feed"},
|
||||
{file = "mysql_connector_python-8.0.31-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:d0ca1ba3e5fb2f2cddcf271c320cd5c368f8d392c034ddab7a1c8dfd19510351"},
|
||||
{file = "mysql_connector_python-8.0.31-cp311-cp311-win_amd64.whl", hash = "sha256:a1d8c1509c740649f352400d50360185e5473371507bb6498ceda0c6e877920c"},
|
||||
{file = "mysql_connector_python-8.0.31-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:447847396d1b51edd9cfe05a8c5ba82836d8ea4866f25f36a836cab322fdc4f0"},
|
||||
{file = "mysql_connector_python-8.0.31-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:5e01a2f50378c13407a32e40dd4d225cfee5996d9d11968f76720ec28aa45421"},
|
||||
{file = "mysql_connector_python-8.0.31-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ac85883ec3b3a9a0e36cacc89b8f5e666206842c432a5f69b09a7687ddf51d4a"},
|
||||
{file = "mysql_connector_python-8.0.31-cp37-cp37m-win_amd64.whl", hash = "sha256:28cb3667be64ebfbd3d477bbd2c71e50d48bd5ed7ba2072dd460ae886d27e88e"},
|
||||
{file = "mysql_connector_python-8.0.31-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:30f4542d4d20357c79604e6bf1a801e71dfc45c759c22b502ca5aa8122c3e859"},
|
||||
{file = "mysql_connector_python-8.0.31-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:e9e5ad544adfc82ffbda2c74685c8c953bce2e212c56f117020079f05e2c68b2"},
|
||||
{file = "mysql_connector_python-8.0.31-cp38-cp38-manylinux1_i686.whl", hash = "sha256:744c976569e81eecce5e8c7e8f80df2a1c3f64414829addc69c64aef8f56d091"},
|
||||
{file = "mysql_connector_python-8.0.31-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:17d6ea22dacca7fa78a73a81f2b186d4c5c6e70b7be314e352526654e9ba4713"},
|
||||
{file = "mysql_connector_python-8.0.31-cp38-cp38-win_amd64.whl", hash = "sha256:ae1b3d03802474a161cce8a97024484d18bef43b86d20114908cbc263817cade"},
|
||||
{file = "mysql_connector_python-8.0.31-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:746df133c677fbe4687da33aad5a711abdd9bd2277bbc350e20f903f07c81ef5"},
|
||||
{file = "mysql_connector_python-8.0.31-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:4d75e6c3a7f18004e8279cbd9f5edc70089d6aaf3cb64374e21098d9bf0b93c4"},
|
||||
{file = "mysql_connector_python-8.0.31-cp39-cp39-manylinux1_i686.whl", hash = "sha256:8ad0d08f3f7c9e48d6d102c7de718e5e44f630f916ff2f4b4ff8a3756b5d10ac"},
|
||||
{file = "mysql_connector_python-8.0.31-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:02526f16eacc3961ff681c5c8455d2306a9b45124f2f012ca75a1eac9ceb5165"},
|
||||
{file = "mysql_connector_python-8.0.31-cp39-cp39-win_amd64.whl", hash = "sha256:b2bbf443f6346e46c26a3e91dd96a428a1038f2d3c5e466541078479c64a1833"},
|
||||
{file = "mysql_connector_python-8.0.31-py2.py3-none-any.whl", hash = "sha256:9be9c4dcae987a2a3f07b2ad984984c24f90887dbfab3c8a971e631ad4ca5ccf"},
|
||||
{file = "mysql-connector-python-8.0.32.tar.gz", hash = "sha256:c2d20b29fd096a0633f9360c275bd2434d4bcf597281991c4b7f1c820cd07b84"},
|
||||
{file = "mysql_connector_python-8.0.32-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:4df11c683924ef34c177a54887dc4844ae735b01c8a29ce6ab92d6d3db7a2757"},
|
||||
{file = "mysql_connector_python-8.0.32-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:4b2d00c9e2cb9e3d11c57ec411226f43aa627607085fbed661cfea1c4dc57f61"},
|
||||
{file = "mysql_connector_python-8.0.32-cp310-cp310-manylinux1_i686.whl", hash = "sha256:992b7a464daa398e86df8c75f7d8cd6044f884ff9087e782120fc8beff96c638"},
|
||||
{file = "mysql_connector_python-8.0.32-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:232095f0c36266510009b0f1214d2823a649efb8bc511dbab9ce8847f66ab08a"},
|
||||
{file = "mysql_connector_python-8.0.32-cp310-cp310-win_amd64.whl", hash = "sha256:fd233c83daaf048c1f9827be984c2721576ae0adf50e139429a06ccd094987d9"},
|
||||
{file = "mysql_connector_python-8.0.32-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:ab13dd6ede0e0e99ba97c73946462c3420625ab6e63fe13b6fc350e30eb3298d"},
|
||||
{file = "mysql_connector_python-8.0.32-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:e722b6ffa5b0d7188eebac792b18bc871643db505bf60d0e6bd2859f31e5ed79"},
|
||||
{file = "mysql_connector_python-8.0.32-cp311-cp311-manylinux1_i686.whl", hash = "sha256:283fe6f647e9d684feb1b7c48fa6a46b1e72c59ecdd6ea2b62392cd80c1a6701"},
|
||||
{file = "mysql_connector_python-8.0.32-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:1c0a11f3ffbf850f2ca7b39e6c82021e8de910ddaeffd856e53dca028d21c923"},
|
||||
{file = "mysql_connector_python-8.0.32-cp311-cp311-win_amd64.whl", hash = "sha256:6cdba2779bcd16af0ceff0a6e50d33e6664a83f8d17d70524beb6f677a6d1fae"},
|
||||
{file = "mysql_connector_python-8.0.32-cp37-cp37m-macosx_12_0_x86_64.whl", hash = "sha256:93b1eb3e07d19a23ccf2605d818aacee0d842b1820bbeef8d0022d8d3d014ab9"},
|
||||
{file = "mysql_connector_python-8.0.32-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:d6b54656ca131a4f0f17b9d0adddc60f84fd982d64e06360026d5b06e5dbf865"},
|
||||
{file = "mysql_connector_python-8.0.32-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:8c5bfedc979d7858402f39c20d66a6cf03ca4c960732a98318126c278535ddb2"},
|
||||
{file = "mysql_connector_python-8.0.32-cp37-cp37m-win_amd64.whl", hash = "sha256:bdd716b1e162fe4b3887f6617e9ddcfa659ba96a9ddb22feeae208a72f43d22f"},
|
||||
{file = "mysql_connector_python-8.0.32-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:bd52a462759aa324a60054c4b44dc8b32007187a328f72be6b58f193d5e32a91"},
|
||||
{file = "mysql_connector_python-8.0.32-cp38-cp38-manylinux1_i686.whl", hash = "sha256:be82357cc7e7e1377e2f4f8c18aa89c8aab6c0117155cf9fcf18e3cd0eb6ac8e"},
|
||||
{file = "mysql_connector_python-8.0.32-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:1f399f3c2599d2591854cd0e0a24c7c399dff21ac5accb6e52e06924de29f3f4"},
|
||||
{file = "mysql_connector_python-8.0.32-cp38-cp38-win_amd64.whl", hash = "sha256:c8bba02501525e1fbbba094a6d8d391d1534e8be41be6396c3e1b9f7d9d13b1c"},
|
||||
{file = "mysql_connector_python-8.0.32-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:145aeb75eefb7425e0a7fb36a4f95ebfe79e06be7c69a4045d34cde95c666dc4"},
|
||||
{file = "mysql_connector_python-8.0.32-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:c990f4c0702d1739076261c4dece1042e1eb18bf34e0d8516d19ec5166a205ce"},
|
||||
{file = "mysql_connector_python-8.0.32-cp39-cp39-manylinux1_i686.whl", hash = "sha256:7f7a69db9e0c36764a6c65377f6174aee46e484520e48659e7aa674415b8e192"},
|
||||
{file = "mysql_connector_python-8.0.32-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:677b5c6dcaec7e2a4bf95b991a869f4d371114f69a0d9a5bb236e988c8f4c376"},
|
||||
{file = "mysql_connector_python-8.0.32-cp39-cp39-win_amd64.whl", hash = "sha256:8c334c41cd1c5bcfa3550340253ef7d9d3b962211f33327c20f69706a0bcce06"},
|
||||
{file = "mysql_connector_python-8.0.32-py2.py3-none-any.whl", hash = "sha256:e0299236297b63bf6cbb61d81a9d400bc01cad4743d1abe5296ef349de15ee53"},
|
||||
]
|
||||
nodeenv = [
|
||||
{file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"},
|
||||
|
@ -2782,7 +2812,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"},
|
||||
|
@ -2852,30 +2885,28 @@ prompt-toolkit = [
|
|||
{file = "prompt_toolkit-3.0.31.tar.gz", hash = "sha256:9ada952c9d1787f52ff6d5f3484d0b4df8952787c087edf6a1f7c2cb1ea88148"},
|
||||
]
|
||||
protobuf = [
|
||||
{file = "protobuf-3.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3cc797c9d15d7689ed507b165cd05913acb992d78b379f6014e013f9ecb20996"},
|
||||
{file = "protobuf-3.20.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:ff8d8fa42675249bb456f5db06c00de6c2f4c27a065955917b28c4f15978b9c3"},
|
||||
{file = "protobuf-3.20.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cd68be2559e2a3b84f517fb029ee611546f7812b1fdd0aa2ecc9bc6ec0e4fdde"},
|
||||
{file = "protobuf-3.20.1-cp310-cp310-win32.whl", hash = "sha256:9016d01c91e8e625141d24ec1b20fed584703e527d28512aa8c8707f105a683c"},
|
||||
{file = "protobuf-3.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:32ca378605b41fd180dfe4e14d3226386d8d1b002ab31c969c366549e66a2bb7"},
|
||||
{file = "protobuf-3.20.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9be73ad47579abc26c12024239d3540e6b765182a91dbc88e23658ab71767153"},
|
||||
{file = "protobuf-3.20.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:097c5d8a9808302fb0da7e20edf0b8d4703274d140fd25c5edabddcde43e081f"},
|
||||
{file = "protobuf-3.20.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e250a42f15bf9d5b09fe1b293bdba2801cd520a9f5ea2d7fb7536d4441811d20"},
|
||||
{file = "protobuf-3.20.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cdee09140e1cd184ba9324ec1df410e7147242b94b5f8b0c64fc89e38a8ba531"},
|
||||
{file = "protobuf-3.20.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:af0ebadc74e281a517141daad9d0f2c5d93ab78e9d455113719a45a49da9db4e"},
|
||||
{file = "protobuf-3.20.1-cp37-cp37m-win32.whl", hash = "sha256:755f3aee41354ae395e104d62119cb223339a8f3276a0cd009ffabfcdd46bb0c"},
|
||||
{file = "protobuf-3.20.1-cp37-cp37m-win_amd64.whl", hash = "sha256:62f1b5c4cd6c5402b4e2d63804ba49a327e0c386c99b1675c8a0fefda23b2067"},
|
||||
{file = "protobuf-3.20.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:06059eb6953ff01e56a25cd02cca1a9649a75a7e65397b5b9b4e929ed71d10cf"},
|
||||
{file = "protobuf-3.20.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:cb29edb9eab15742d791e1025dd7b6a8f6fcb53802ad2f6e3adcb102051063ab"},
|
||||
{file = "protobuf-3.20.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:69ccfdf3657ba59569c64295b7d51325f91af586f8d5793b734260dfe2e94e2c"},
|
||||
{file = "protobuf-3.20.1-cp38-cp38-win32.whl", hash = "sha256:dd5789b2948ca702c17027c84c2accb552fc30f4622a98ab5c51fcfe8c50d3e7"},
|
||||
{file = "protobuf-3.20.1-cp38-cp38-win_amd64.whl", hash = "sha256:77053d28427a29987ca9caf7b72ccafee011257561259faba8dd308fda9a8739"},
|
||||
{file = "protobuf-3.20.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6f50601512a3d23625d8a85b1638d914a0970f17920ff39cec63aaef80a93fb7"},
|
||||
{file = "protobuf-3.20.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:284f86a6207c897542d7e956eb243a36bb8f9564c1742b253462386e96c6b78f"},
|
||||
{file = "protobuf-3.20.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7403941f6d0992d40161aa8bb23e12575637008a5a02283a930addc0508982f9"},
|
||||
{file = "protobuf-3.20.1-cp39-cp39-win32.whl", hash = "sha256:db977c4ca738dd9ce508557d4fce0f5aebd105e158c725beec86feb1f6bc20d8"},
|
||||
{file = "protobuf-3.20.1-cp39-cp39-win_amd64.whl", hash = "sha256:7e371f10abe57cee5021797126c93479f59fccc9693dafd6bd5633ab67808a91"},
|
||||
{file = "protobuf-3.20.1-py2.py3-none-any.whl", hash = "sha256:adfc6cf69c7f8c50fd24c793964eef18f0ac321315439d94945820612849c388"},
|
||||
{file = "protobuf-3.20.1.tar.gz", hash = "sha256:adc31566d027f45efe3f44eeb5b1f329da43891634d61c75a5944e9be6dd42c9"},
|
||||
{file = "protobuf-3.20.3-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:f4bd856d702e5b0d96a00ec6b307b0f51c1982c2bf9c0052cf9019e9a544ba99"},
|
||||
{file = "protobuf-3.20.3-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9aae4406ea63d825636cc11ffb34ad3379335803216ee3a856787bcf5ccc751e"},
|
||||
{file = "protobuf-3.20.3-cp310-cp310-win32.whl", hash = "sha256:28545383d61f55b57cf4df63eebd9827754fd2dc25f80c5253f9184235db242c"},
|
||||
{file = "protobuf-3.20.3-cp310-cp310-win_amd64.whl", hash = "sha256:67a3598f0a2dcbc58d02dd1928544e7d88f764b47d4a286202913f0b2801c2e7"},
|
||||
{file = "protobuf-3.20.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:899dc660cd599d7352d6f10d83c95df430a38b410c1b66b407a6b29265d66469"},
|
||||
{file = "protobuf-3.20.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e64857f395505ebf3d2569935506ae0dfc4a15cb80dc25261176c784662cdcc4"},
|
||||
{file = "protobuf-3.20.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:d9e4432ff660d67d775c66ac42a67cf2453c27cb4d738fc22cb53b5d84c135d4"},
|
||||
{file = "protobuf-3.20.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:74480f79a023f90dc6e18febbf7b8bac7508420f2006fabd512013c0c238f454"},
|
||||
{file = "protobuf-3.20.3-cp37-cp37m-win32.whl", hash = "sha256:b6cc7ba72a8850621bfec987cb72623e703b7fe2b9127a161ce61e61558ad905"},
|
||||
{file = "protobuf-3.20.3-cp37-cp37m-win_amd64.whl", hash = "sha256:8c0c984a1b8fef4086329ff8dd19ac77576b384079247c770f29cc8ce3afa06c"},
|
||||
{file = "protobuf-3.20.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:de78575669dddf6099a8a0f46a27e82a1783c557ccc38ee620ed8cc96d3be7d7"},
|
||||
{file = "protobuf-3.20.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:f4c42102bc82a51108e449cbb32b19b180022941c727bac0cfd50170341f16ee"},
|
||||
{file = "protobuf-3.20.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:44246bab5dd4b7fbd3c0c80b6f16686808fab0e4aca819ade6e8d294a29c7050"},
|
||||
{file = "protobuf-3.20.3-cp38-cp38-win32.whl", hash = "sha256:c02ce36ec760252242a33967d51c289fd0e1c0e6e5cc9397e2279177716add86"},
|
||||
{file = "protobuf-3.20.3-cp38-cp38-win_amd64.whl", hash = "sha256:447d43819997825d4e71bf5769d869b968ce96848b6479397e29fc24c4a5dfe9"},
|
||||
{file = "protobuf-3.20.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:398a9e0c3eaceb34ec1aee71894ca3299605fa8e761544934378bbc6c97de23b"},
|
||||
{file = "protobuf-3.20.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bf01b5720be110540be4286e791db73f84a2b721072a3711efff6c324cdf074b"},
|
||||
{file = "protobuf-3.20.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:daa564862dd0d39c00f8086f88700fdbe8bc717e993a21e90711acfed02f2402"},
|
||||
{file = "protobuf-3.20.3-cp39-cp39-win32.whl", hash = "sha256:819559cafa1a373b7096a482b504ae8a857c89593cf3a25af743ac9ecbd23480"},
|
||||
{file = "protobuf-3.20.3-cp39-cp39-win_amd64.whl", hash = "sha256:03038ac1cfbc41aa21f6afcbcd357281d7521b4157926f30ebecc8d4ea59dcb7"},
|
||||
{file = "protobuf-3.20.3-py2.py3-none-any.whl", hash = "sha256:a7ca6d488aa8ff7f329d4c545b2dbad8ac31464f1d8b1c87ad1346717731e4db"},
|
||||
{file = "protobuf-3.20.3.tar.gz", hash = "sha256:2e3427429c9cffebf259491be0af70189607f365c2f41c7c3764af6f337105f2"},
|
||||
]
|
||||
psycopg2 = [
|
||||
{file = "psycopg2-2.9.4-cp310-cp310-win32.whl", hash = "sha256:8de6a9fc5f42fa52f559e65120dcd7502394692490c98fed1221acf0819d7797"},
|
||||
|
|
|
@ -27,10 +27,13 @@ flask-marshmallow = "*"
|
|||
flask-migrate = "*"
|
||||
flask-restful = "*"
|
||||
werkzeug = "*"
|
||||
#SpiffWorkflow = {git = "https://github.com/sartography/SpiffWorkflow", rev = "main"}
|
||||
SpiffWorkflow = {develop = true, path = "/home/dan/code/workflow/SpiffWorkflow" }
|
||||
# temporarily switch off main to fix CI because poetry export doesn't capture the revision if it's not here (it ignores the lock)
|
||||
SpiffWorkflow = {git = "https://github.com/sartography/SpiffWorkflow", rev = "main"}
|
||||
# SpiffWorkflow = {develop = true, path = "../SpiffWorkflow" }
|
||||
sentry-sdk = "^1.10"
|
||||
sphinx-autoapi = "^2.0"
|
||||
flask-bpmn = {git = "https://github.com/sartography/flask-bpmn", rev = "main"}
|
||||
# flask-bpmn = {develop = true, path = "../flask-bpmn"}
|
||||
mysql-connector-python = "*"
|
||||
pytest-flask = "^1.2.0"
|
||||
pytest-flask-sqlalchemy = "^1.1.0"
|
||||
|
|
|
@ -125,7 +125,11 @@ def create_app() -> flask.app.Flask:
|
|||
|
||||
app.json = MyJSONEncoder(app)
|
||||
|
||||
if app.config["RUN_BACKGROUND_SCHEDULER"]:
|
||||
# do not start the scheduler twice in flask debug mode
|
||||
if (
|
||||
app.config["RUN_BACKGROUND_SCHEDULER"]
|
||||
and os.environ.get("WERKZEUG_RUN_MAIN") != "true"
|
||||
):
|
||||
start_scheduler(app)
|
||||
|
||||
configure_sentry(app)
|
||||
|
|
|
@ -10,7 +10,7 @@ SPIFFWORKFLOW_BACKEND_LOG_LEVEL = environ.get(
|
|||
)
|
||||
|
||||
RUN_BACKGROUND_SCHEDULER = (
|
||||
environ.get("RUN_BACKGROUND_SCHEDULER", default="true") == "true"
|
||||
environ.get("RUN_BACKGROUND_SCHEDULER", default="false") == "true"
|
||||
)
|
||||
GIT_CLONE_URL_FOR_PUBLISHING = environ.get(
|
||||
"GIT_CLONE_URL", default="https://github.com/sartography/sample-process-models.git"
|
||||
|
|
|
@ -20,11 +20,29 @@ from spiffworkflow_backend.routes.process_api_blueprint import (
|
|||
_un_modify_modified_process_model_id,
|
||||
)
|
||||
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
||||
from spiffworkflow_backend.services.process_model_service import (
|
||||
ProcessModelWithInstancesNotDeletableError,
|
||||
)
|
||||
|
||||
|
||||
def process_group_create(body: dict) -> flask.wrappers.Response:
|
||||
"""Add_process_group."""
|
||||
process_group = ProcessGroup(**body)
|
||||
|
||||
if ProcessModelService.is_process_model_identifier(process_group.id):
|
||||
raise ApiError(
|
||||
error_code="process_model_with_id_already_exists",
|
||||
message=f"Process Model with given id already exists: {process_group.id}",
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
if ProcessModelService.is_process_group_identifier(process_group.id):
|
||||
raise ApiError(
|
||||
error_code="process_group_with_id_already_exists",
|
||||
message=f"Process Group with given id already exists: {process_group.id}",
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
ProcessModelService.add_process_group(process_group)
|
||||
_commit_and_push_to_git(
|
||||
f"User: {g.user.username} added process group {process_group.id}"
|
||||
|
@ -35,7 +53,16 @@ def process_group_create(body: dict) -> flask.wrappers.Response:
|
|||
def process_group_delete(modified_process_group_id: str) -> flask.wrappers.Response:
|
||||
"""Process_group_delete."""
|
||||
process_group_id = _un_modify_modified_process_model_id(modified_process_group_id)
|
||||
ProcessModelService().process_group_delete(process_group_id)
|
||||
|
||||
try:
|
||||
ProcessModelService().process_group_delete(process_group_id)
|
||||
except ProcessModelWithInstancesNotDeletableError as exception:
|
||||
raise ApiError(
|
||||
error_code="existing_instances",
|
||||
message=str(exception),
|
||||
status_code=400,
|
||||
) from exception
|
||||
|
||||
_commit_and_push_to_git(
|
||||
f"User: {g.user.username} deleted process group {process_group_id}"
|
||||
)
|
||||
|
@ -54,6 +81,13 @@ def process_group_update(
|
|||
}
|
||||
|
||||
process_group_id = _un_modify_modified_process_model_id(modified_process_group_id)
|
||||
if not ProcessModelService.is_process_group_identifier(process_group_id):
|
||||
raise ApiError(
|
||||
error_code="process_group_does_not_exist",
|
||||
message=f"Process Group with given id does not exist: {process_group_id}",
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
process_group = ProcessGroup(id=process_group_id, **body_filtered)
|
||||
ProcessModelService.update_process_group(process_group)
|
||||
_commit_and_push_to_git(
|
||||
|
|
|
@ -182,9 +182,17 @@ def process_instance_log_list(
|
|||
)
|
||||
if not detailed:
|
||||
log_query = log_query.filter(
|
||||
or_(
|
||||
# this was the previous implementation, where we only show completed tasks and skipped tasks.
|
||||
# maybe we want to iterate on this in the future (in a third tab under process instance logs?)
|
||||
# or_(
|
||||
# SpiffLoggingModel.message.in_(["State change to COMPLETED"]), # type: ignore
|
||||
# SpiffLoggingModel.message.like("Skipped task %"), # type: ignore
|
||||
# )
|
||||
and_(
|
||||
SpiffLoggingModel.message.in_(["State change to COMPLETED"]), # type: ignore
|
||||
SpiffLoggingModel.message.like("Skipped task %"), # type: ignore
|
||||
SpiffLoggingModel.bpmn_task_type.in_( # type: ignore
|
||||
["Default Throwing Event", "End Event", "Default Start Event"]
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -39,6 +39,9 @@ from spiffworkflow_backend.services.process_instance_report_service import (
|
|||
ProcessInstanceReportService,
|
||||
)
|
||||
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
||||
from spiffworkflow_backend.services.process_model_service import (
|
||||
ProcessModelWithInstancesNotDeletableError,
|
||||
)
|
||||
from spiffworkflow_backend.services.spec_file_service import (
|
||||
ProcessModelFileInvalidError,
|
||||
)
|
||||
|
@ -75,6 +78,24 @@ def process_model_create(
|
|||
status_code=400,
|
||||
)
|
||||
|
||||
if ProcessModelService.is_process_model_identifier(process_model_info.id):
|
||||
raise ApiError(
|
||||
error_code="process_model_with_id_already_exists",
|
||||
message=(
|
||||
f"Process Model with given id already exists: {process_model_info.id}"
|
||||
),
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
if ProcessModelService.is_process_group_identifier(process_model_info.id):
|
||||
raise ApiError(
|
||||
error_code="process_group_with_id_already_exists",
|
||||
message=(
|
||||
f"Process Group with given id already exists: {process_model_info.id}"
|
||||
),
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
ProcessModelService.add_process_model(process_model_info)
|
||||
_commit_and_push_to_git(
|
||||
f"User: {g.user.username} created process model {process_model_info.id}"
|
||||
|
@ -91,7 +112,15 @@ def process_model_delete(
|
|||
) -> flask.wrappers.Response:
|
||||
"""Process_model_delete."""
|
||||
process_model_identifier = modified_process_model_identifier.replace(":", "/")
|
||||
ProcessModelService().process_model_delete(process_model_identifier)
|
||||
try:
|
||||
ProcessModelService().process_model_delete(process_model_identifier)
|
||||
except ProcessModelWithInstancesNotDeletableError as exception:
|
||||
raise ApiError(
|
||||
error_code="existing_instances",
|
||||
message=str(exception),
|
||||
status_code=400,
|
||||
) from exception
|
||||
|
||||
_commit_and_push_to_git(
|
||||
f"User: {g.user.username} deleted process model {process_model_identifier}"
|
||||
)
|
||||
|
|
|
@ -49,7 +49,7 @@ def script_unit_test_create(
|
|||
|
||||
# TODO: move this to an xml service or something
|
||||
file_contents = SpecFileService.get_data(process_model, file.name)
|
||||
bpmn_etree_element = etree.fromstring(file_contents)
|
||||
bpmn_etree_element = SpecFileService.get_etree_from_xml_bytes(file_contents)
|
||||
|
||||
nsmap = bpmn_etree_element.nsmap
|
||||
spiff_element_maker = ElementMaker(
|
||||
|
|
|
@ -303,7 +303,6 @@ def login_api() -> Response:
|
|||
|
||||
|
||||
def login_api_return(code: str, state: str, session_state: str) -> str:
|
||||
"""Login_api_return."""
|
||||
state_dict = ast.literal_eval(base64.b64decode(state).decode("utf-8"))
|
||||
state_dict["redirect_url"]
|
||||
|
||||
|
|
|
@ -692,9 +692,8 @@ class ProcessInstanceProcessor:
|
|||
):
|
||||
continue
|
||||
|
||||
subprocesses_by_child_task_ids[
|
||||
task_id
|
||||
] = subprocesses_by_child_task_ids[subprocess_id]
|
||||
subprocesses_by_child_task_ids[task_id] =\
|
||||
subprocesses_by_child_task_ids[subprocess_id]
|
||||
self.get_highest_level_calling_subprocesses_by_child_task_ids(
|
||||
subprocesses_by_child_task_ids, task_typename_by_task_id
|
||||
)
|
||||
|
@ -1022,10 +1021,10 @@ class ProcessInstanceProcessor:
|
|||
data = SpecFileService.get_data(process_model_info, file.name)
|
||||
try:
|
||||
if file.type == FileType.bpmn.value:
|
||||
bpmn: etree.Element = etree.fromstring(data)
|
||||
bpmn: etree.Element = SpecFileService.get_etree_from_xml_bytes(data)
|
||||
parser.add_bpmn_xml(bpmn, filename=file.name)
|
||||
elif file.type == FileType.dmn.value:
|
||||
dmn: etree.Element = etree.fromstring(data)
|
||||
dmn: etree.Element = SpecFileService.get_etree_from_xml_bytes(data)
|
||||
parser.add_dmn_xml(dmn, filename=file.name)
|
||||
except XMLSyntaxError as xse:
|
||||
raise ApiError(
|
||||
|
@ -1075,9 +1074,13 @@ class ProcessInstanceProcessor:
|
|||
if bpmn_process_instance.is_completed():
|
||||
return ProcessInstanceStatus.complete
|
||||
user_tasks = bpmn_process_instance.get_ready_user_tasks()
|
||||
waiting_tasks = bpmn_process_instance.get_tasks(TaskState.WAITING)
|
||||
if len(waiting_tasks) > 0:
|
||||
return ProcessInstanceStatus.waiting
|
||||
|
||||
# if the process instance has status "waiting" it will get picked up
|
||||
# by background processing. when that happens it can potentially overwrite
|
||||
# human tasks which is bad because we cache them with the previous id's.
|
||||
# waiting_tasks = bpmn_process_instance.get_tasks(TaskState.WAITING)
|
||||
# if len(waiting_tasks) > 0:
|
||||
# return ProcessInstanceStatus.waiting
|
||||
if len(user_tasks) > 0:
|
||||
return ProcessInstanceStatus.user_input_required
|
||||
else:
|
||||
|
|
|
@ -26,6 +26,10 @@ from spiffworkflow_backend.services.user_service import UserService
|
|||
T = TypeVar("T")
|
||||
|
||||
|
||||
class ProcessModelWithInstancesNotDeletableError(Exception):
|
||||
"""ProcessModelWithInstancesNotDeletableError."""
|
||||
|
||||
|
||||
class ProcessModelService(FileSystemService):
|
||||
"""ProcessModelService."""
|
||||
|
||||
|
@ -44,7 +48,7 @@ class ProcessModelService(FileSystemService):
|
|||
return path.replace(os.sep, "/")
|
||||
|
||||
@classmethod
|
||||
def is_group(cls, path: str) -> bool:
|
||||
def is_process_group(cls, path: str) -> bool:
|
||||
"""Is_group."""
|
||||
group_json_path = os.path.join(path, cls.PROCESS_GROUP_JSON_FILE)
|
||||
if os.path.exists(group_json_path):
|
||||
|
@ -52,8 +56,8 @@ class ProcessModelService(FileSystemService):
|
|||
return False
|
||||
|
||||
@classmethod
|
||||
def is_group_identifier(cls, process_group_identifier: str) -> bool:
|
||||
"""Is_group_identifier."""
|
||||
def is_process_group_identifier(cls, process_group_identifier: str) -> bool:
|
||||
"""Is_process_group_identifier."""
|
||||
if os.path.exists(FileSystemService.root_path()):
|
||||
process_group_path = os.path.abspath(
|
||||
os.path.join(
|
||||
|
@ -63,21 +67,21 @@ class ProcessModelService(FileSystemService):
|
|||
),
|
||||
)
|
||||
)
|
||||
return cls.is_group(process_group_path)
|
||||
return cls.is_process_group(process_group_path)
|
||||
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def is_model(cls, path: str) -> bool:
|
||||
"""Is_model."""
|
||||
def is_process_model(cls, path: str) -> bool:
|
||||
"""Is_process_model."""
|
||||
model_json_path = os.path.join(path, cls.PROCESS_MODEL_JSON_FILE)
|
||||
if os.path.exists(model_json_path):
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def is_model_identifier(cls, process_model_identifier: str) -> bool:
|
||||
"""Is_model_identifier."""
|
||||
def is_process_model_identifier(cls, process_model_identifier: str) -> bool:
|
||||
"""Is_process_model_identifier."""
|
||||
if os.path.exists(FileSystemService.root_path()):
|
||||
process_model_path = os.path.abspath(
|
||||
os.path.join(
|
||||
|
@ -87,7 +91,7 @@ class ProcessModelService(FileSystemService):
|
|||
),
|
||||
)
|
||||
)
|
||||
return cls.is_model(process_model_path)
|
||||
return cls.is_process_model(process_model_path)
|
||||
|
||||
return False
|
||||
|
||||
|
@ -129,7 +133,9 @@ class ProcessModelService(FileSystemService):
|
|||
def save_process_model(cls, process_model: ProcessModelInfo) -> None:
|
||||
"""Save_process_model."""
|
||||
process_model_path = os.path.abspath(
|
||||
os.path.join(FileSystemService.root_path(), process_model.id)
|
||||
os.path.join(
|
||||
FileSystemService.root_path(), process_model.id_for_file_path()
|
||||
)
|
||||
)
|
||||
os.makedirs(process_model_path, exist_ok=True)
|
||||
json_path = os.path.abspath(
|
||||
|
@ -150,12 +156,9 @@ class ProcessModelService(FileSystemService):
|
|||
ProcessInstanceModel.process_model_identifier == process_model_id
|
||||
).all()
|
||||
if len(instances) > 0:
|
||||
raise ApiError(
|
||||
error_code="existing_instances",
|
||||
message=(
|
||||
f"We cannot delete the model `{process_model_id}`, there are"
|
||||
" existing instances that depend on it."
|
||||
),
|
||||
raise ProcessModelWithInstancesNotDeletableError(
|
||||
f"We cannot delete the model `{process_model_id}`, there are"
|
||||
" existing instances that depend on it."
|
||||
)
|
||||
process_model = self.get_process_model(process_model_id)
|
||||
path = self.workflow_path(process_model)
|
||||
|
@ -196,7 +199,7 @@ class ProcessModelService(FileSystemService):
|
|||
model_path = os.path.abspath(
|
||||
os.path.join(FileSystemService.root_path(), process_model_id)
|
||||
)
|
||||
if cls.is_model(model_path):
|
||||
if cls.is_process_model(model_path):
|
||||
return cls.get_process_model_from_relative_path(process_model_id)
|
||||
raise ProcessEntityNotFoundError("process_model_not_found")
|
||||
|
||||
|
@ -300,7 +303,7 @@ class ProcessModelService(FileSystemService):
|
|||
FileSystemService.id_string_to_relative_path(process_group_id),
|
||||
)
|
||||
)
|
||||
if cls.is_group(process_group_path):
|
||||
if cls.is_process_group(process_group_path):
|
||||
return cls.find_or_create_process_group(
|
||||
process_group_path,
|
||||
find_direct_nested_items=find_direct_nested_items,
|
||||
|
@ -348,7 +351,7 @@ class ProcessModelService(FileSystemService):
|
|||
for _root, dirs, _files in os.walk(group_path):
|
||||
for dir in dirs:
|
||||
model_dir = os.path.join(group_path, dir)
|
||||
if ProcessModelService.is_model(model_dir):
|
||||
if ProcessModelService.is_process_model(model_dir):
|
||||
process_model = self.get_process_model(model_dir)
|
||||
all_nested_models.append(process_model)
|
||||
return all_nested_models
|
||||
|
@ -366,13 +369,10 @@ class ProcessModelService(FileSystemService):
|
|||
if len(instances) > 0:
|
||||
problem_models.append(process_model)
|
||||
if len(problem_models) > 0:
|
||||
raise ApiError(
|
||||
error_code="existing_instances",
|
||||
message=(
|
||||
f"We cannot delete the group `{process_group_id}`, there are"
|
||||
" models with existing instances inside the group."
|
||||
f" {problem_models}"
|
||||
),
|
||||
raise ProcessModelWithInstancesNotDeletableError(
|
||||
f"We cannot delete the group `{process_group_id}`, there are"
|
||||
" models with existing instances inside the group."
|
||||
f" {problem_models}"
|
||||
)
|
||||
shutil.rmtree(path)
|
||||
self.cleanup_process_group_display_order()
|
||||
|
@ -403,7 +403,7 @@ class ProcessModelService(FileSystemService):
|
|||
process_groups = []
|
||||
for item in directory_items:
|
||||
# if item.is_dir() and not item.name[0] == ".":
|
||||
if item.is_dir() and cls.is_group(item): # type: ignore
|
||||
if item.is_dir() and cls.is_process_group(item): # type: ignore
|
||||
scanned_process_group = cls.find_or_create_process_group(item.path)
|
||||
process_groups.append(scanned_process_group)
|
||||
return process_groups
|
||||
|
@ -450,12 +450,12 @@ class ProcessModelService(FileSystemService):
|
|||
for nested_item in nested_items:
|
||||
if nested_item.is_dir():
|
||||
# TODO: check whether this is a group or model
|
||||
if cls.is_group(nested_item.path):
|
||||
if cls.is_process_group(nested_item.path):
|
||||
# This is a nested group
|
||||
process_group.process_groups.append(
|
||||
cls.find_or_create_process_group(nested_item.path)
|
||||
)
|
||||
elif ProcessModelService.is_model(nested_item.path):
|
||||
elif ProcessModelService.is_process_model(nested_item.path):
|
||||
process_group.process_models.append(
|
||||
cls.__scan_process_model(
|
||||
nested_item.path,
|
||||
|
|
|
@ -5,6 +5,7 @@ from datetime import datetime
|
|||
from typing import List
|
||||
from typing import Optional
|
||||
|
||||
from flask_bpmn.models.db import db
|
||||
from lxml import etree # type: ignore
|
||||
from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnValidator # type: ignore
|
||||
|
||||
|
@ -93,6 +94,12 @@ class SpecFileService(FileSystemService):
|
|||
process_model_info, file.name, file_contents
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_etree_from_xml_bytes(cls, binary_data: bytes) -> etree.Element:
|
||||
"""Get_etree_from_xml_bytes."""
|
||||
etree_xml_parser = etree.XMLParser(resolve_entities=False)
|
||||
return etree.fromstring(binary_data, parser=etree_xml_parser)
|
||||
|
||||
@classmethod
|
||||
def get_references_for_file_contents(
|
||||
cls, process_model_info: ProcessModelInfo, file_name: str, binary_data: bytes
|
||||
|
@ -118,13 +125,13 @@ class SpecFileService(FileSystemService):
|
|||
correlations = {}
|
||||
start_messages = []
|
||||
if file_type.value == FileType.bpmn.value:
|
||||
parser.add_bpmn_xml(etree.fromstring(binary_data))
|
||||
parser.add_bpmn_xml(cls.get_etree_from_xml_bytes(binary_data))
|
||||
parser_type = "process"
|
||||
sub_parsers = list(parser.process_parsers.values())
|
||||
messages = parser.messages
|
||||
correlations = parser.correlations
|
||||
elif file_type.value == FileType.dmn.value:
|
||||
parser.add_dmn_xml(etree.fromstring(binary_data))
|
||||
parser.add_dmn_xml(cls.get_etree_from_xml_bytes(binary_data))
|
||||
sub_parsers = list(parser.dmn_parsers.values())
|
||||
parser_type = "decision"
|
||||
else:
|
||||
|
@ -172,9 +179,13 @@ class SpecFileService(FileSystemService):
|
|||
validator = BpmnValidator()
|
||||
parser = MyCustomParser(validator=validator)
|
||||
try:
|
||||
parser.add_bpmn_xml(etree.fromstring(binary_data), filename=file_name)
|
||||
parser.add_bpmn_xml(
|
||||
cls.get_etree_from_xml_bytes(binary_data), filename=file_name
|
||||
)
|
||||
except Exception as exception:
|
||||
raise ProcessModelFileInvalidError(str(exception))
|
||||
raise ProcessModelFileInvalidError(
|
||||
f"Received error trying to parse bpmn xml: {str(exception)}"
|
||||
) from exception
|
||||
|
||||
@classmethod
|
||||
def update_file(
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
|
||||
<bpmn:process id="ManualTaskToCallFromCallActivityToTestWaitingLogs" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_1nxz6rd</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_1nxz6rd" sourceRef="StartEvent_1" targetRef="the_manual_task" />
|
||||
<bpmn:endEvent id="Event_19yodox">
|
||||
<bpmn:incoming>Flow_1jtitb1</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_1jtitb1" sourceRef="the_manual_task" targetRef="Event_19yodox" />
|
||||
<bpmn:manualTask id="the_manual_task" name="The Manual Task">
|
||||
<bpmn:extensionElements>
|
||||
<spiffworkflow:instructionsForEndUser>NOOOOOOOOOOOOOOOOOO!!!!!!!!!!</spiffworkflow:instructionsForEndUser>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_1nxz6rd</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_1jtitb1</bpmn:outgoing>
|
||||
</bpmn:manualTask>
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="ManualTaskToCallFromCallActivityToTestWaitingLogs">
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="179" y="159" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_19yodox_di" bpmnElement="Event_19yodox">
|
||||
<dc:Bounds x="432" y="159" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0tl8vo6_di" bpmnElement="the_manual_task">
|
||||
<dc:Bounds x="270" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_1nxz6rd_di" bpmnElement="Flow_1nxz6rd">
|
||||
<di:waypoint x="215" y="177" />
|
||||
<di:waypoint x="270" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1jtitb1_di" bpmnElement="Flow_1jtitb1">
|
||||
<di:waypoint x="370" y="177" />
|
||||
<di:waypoint x="432" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
|
||||
<bpmn:process id="Process_zywnms5" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_0fdzi5f</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_0fdzi5f" sourceRef="StartEvent_1" targetRef="call_activity_to_human_task" />
|
||||
<bpmn:endEvent id="Event_1dzrts2">
|
||||
<bpmn:incoming>Flow_0ii0wgu</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_0ii0wgu" sourceRef="call_activity_to_human_task" targetRef="Event_1dzrts2" />
|
||||
<bpmn:callActivity id="call_activity_to_human_task" name="Call Activity To Human Task" calledElement="ManualTaskToCallFromCallActivityToTestWaitingLogs">
|
||||
<bpmn:incoming>Flow_0fdzi5f</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0ii0wgu</bpmn:outgoing>
|
||||
</bpmn:callActivity>
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_zywnms5">
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="179" y="159" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_1dzrts2_di" bpmnElement="Event_1dzrts2">
|
||||
<dc:Bounds x="432" y="159" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0qb9821_di" bpmnElement="call_activity_to_human_task">
|
||||
<dc:Bounds x="270" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_0fdzi5f_di" bpmnElement="Flow_0fdzi5f">
|
||||
<di:waypoint x="215" y="177" />
|
||||
<di:waypoint x="270" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0ii0wgu_di" bpmnElement="Flow_0ii0wgu">
|
||||
<di:waypoint x="370" y="177" />
|
||||
<di:waypoint x="432" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -0,0 +1 @@
|
|||
THIS_STRING_SHOULD_NOT_EXIST_ITS_SECRET
|
|
@ -0,0 +1,6 @@
|
|||
<!--?xml version="1.0" ?-->
|
||||
<!DOCTYPE replace [<!ENTITY ent SYSTEM "file://{{FULL_PATH_TO_FILE}}"> ]>
|
||||
<userInfo>
|
||||
<firstName>John</firstName>
|
||||
<lastName>&ent;</lastName>
|
||||
</userInfo>
|
|
@ -139,7 +139,7 @@ class BaseTest:
|
|||
process_group_path = os.path.abspath(
|
||||
os.path.join(FileSystemService.root_path(), process_group_id)
|
||||
)
|
||||
if ProcessModelService.is_group(process_group_path):
|
||||
if ProcessModelService.is_process_group(process_group_path):
|
||||
if exception_notification_addresses is None:
|
||||
exception_notification_addresses = []
|
||||
|
||||
|
@ -173,11 +173,11 @@ class BaseTest:
|
|||
" model"
|
||||
)
|
||||
|
||||
def get_test_data_file_contents(
|
||||
def get_test_data_file_full_path(
|
||||
self, file_name: str, process_model_test_data_dir: str
|
||||
) -> bytes:
|
||||
) -> str:
|
||||
"""Get_test_data_file_contents."""
|
||||
file_full_path = os.path.join(
|
||||
return os.path.join(
|
||||
current_app.instance_path,
|
||||
"..",
|
||||
"..",
|
||||
|
@ -186,6 +186,14 @@ class BaseTest:
|
|||
process_model_test_data_dir,
|
||||
file_name,
|
||||
)
|
||||
|
||||
def get_test_data_file_contents(
|
||||
self, file_name: str, process_model_test_data_dir: str
|
||||
) -> bytes:
|
||||
"""Get_test_data_file_contents."""
|
||||
file_full_path = self.get_test_data_file_full_path(
|
||||
file_name, process_model_test_data_dir
|
||||
)
|
||||
with open(file_full_path, "rb") as file:
|
||||
return file.read()
|
||||
|
||||
|
@ -251,9 +259,9 @@ class BaseTest:
|
|||
|
||||
There must be an existing process model to instantiate.
|
||||
"""
|
||||
if not ProcessModelService.is_model_identifier(test_process_model_id):
|
||||
if not ProcessModelService.is_process_model_identifier(test_process_model_id):
|
||||
dirname = os.path.dirname(test_process_model_id)
|
||||
if not ProcessModelService.is_group_identifier(dirname):
|
||||
if not ProcessModelService.is_process_group_identifier(dirname):
|
||||
process_group = ProcessGroup(id=dirname, display_name=dirname)
|
||||
ProcessModelService.add_process_group(process_group)
|
||||
basename = os.path.basename(test_process_model_id)
|
||||
|
|
|
@ -57,7 +57,7 @@ class TestLoggingService(BaseTest):
|
|||
assert response.status_code == 200
|
||||
|
||||
log_response = client.get(
|
||||
f"/v1.0/logs/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}",
|
||||
f"/v1.0/logs/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}?detailed=true",
|
||||
headers=headers,
|
||||
)
|
||||
assert log_response.status_code == 200
|
||||
|
|
|
@ -18,15 +18,15 @@ def test_start_dates_are_one_hour_apart(app: Flask) -> None:
|
|||
)
|
||||
group_identifier = os.path.dirname(process_model_identifier)
|
||||
parent_group_identifier = os.path.dirname(group_identifier)
|
||||
if not ProcessModelService.is_group(parent_group_identifier):
|
||||
if not ProcessModelService.is_process_group(parent_group_identifier):
|
||||
process_group = ProcessGroup(
|
||||
id=parent_group_identifier, display_name=parent_group_identifier
|
||||
)
|
||||
ProcessModelService.add_process_group(process_group)
|
||||
if not ProcessModelService.is_group(group_identifier):
|
||||
if not ProcessModelService.is_process_group(group_identifier):
|
||||
process_group = ProcessGroup(id=group_identifier, display_name=group_identifier)
|
||||
ProcessModelService.add_process_group(process_group)
|
||||
if not ProcessModelService.is_model(process_model_identifier):
|
||||
if not ProcessModelService.is_process_model(process_model_identifier):
|
||||
process_model = ProcessModelInfo(
|
||||
id=process_model_identifier,
|
||||
display_name=process_model_identifier,
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
"""Test_process_instance_processor."""
|
||||
import os
|
||||
from flask.app import Flask
|
||||
from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel
|
||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
|
||||
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
from spiffworkflow_backend.services.process_instance_processor import (
|
||||
ProcessInstanceProcessor,
|
||||
)
|
||||
|
||||
|
||||
class TestProcessInstanceService(BaseTest):
|
||||
"""TestProcessInstanceService."""
|
||||
|
||||
def test_does_not_log_set_data_when_calling_engine_steps_on_waiting_call_activity(
|
||||
self,
|
||||
app: Flask,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_super_admin_user: UserModel,
|
||||
) -> None:
|
||||
"""Test_does_not_log_set_data_when_calling_engine_steps_on_waiting_call_activity."""
|
||||
tmp_file = '/tmp/testfile.txt'
|
||||
if os.path.isfile(tmp_file):
|
||||
os.remove(tmp_file)
|
||||
process_model = load_test_spec(
|
||||
process_model_id="test_group/call-activity-to-human-task",
|
||||
process_model_source_directory="call-activity-to-human-task",
|
||||
)
|
||||
process_instance = self.create_process_instance_from_process_model(
|
||||
process_model=process_model, user=with_super_admin_user
|
||||
)
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
processor.do_engine_steps(save=True)
|
||||
|
||||
process_instance_logs = SpiffLoggingModel.query.filter_by(process_instance_id=process_instance.id).all()
|
||||
initial_length = len(process_instance_logs)
|
||||
|
||||
# logs should NOT increase after running this a second time since it's just waiting on a human task
|
||||
print("HEY NOW")
|
||||
with open(tmp_file, 'w') as f:
|
||||
f.write("HEY")
|
||||
processor.do_engine_steps(save=True)
|
||||
process_instance_logs = SpiffLoggingModel.query.filter_by(process_instance_id=process_instance.id).all()
|
||||
assert len(process_instance_logs) == initial_length
|
|
@ -1,9 +1,12 @@
|
|||
"""Test_message_service."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
from flask import Flask
|
||||
from flask.testing import FlaskClient
|
||||
from flask_bpmn.models.db import db
|
||||
from lxml import etree # type: ignore
|
||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
|
||||
|
||||
|
@ -237,3 +240,29 @@ class TestSpecFileService(BaseTest):
|
|||
|
||||
full_file_path = SpecFileService.full_file_path(process_model, "bad_xml.bpmn")
|
||||
assert not os.path.isfile(full_file_path)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.platform == "win32",
|
||||
reason="tmp file path is not valid xml for windows and it doesn't matter",
|
||||
)
|
||||
def test_does_not_evaluate_entities(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
) -> None:
|
||||
"""Test_does_not_evaluate_entities."""
|
||||
string_replacement = b"THIS_STRING_SHOULD_NOT_EXIST_ITS_SECRET"
|
||||
tmp_file = os.path.normpath(
|
||||
self.get_test_data_file_full_path("file_to_inject", "xml_with_entity")
|
||||
)
|
||||
file_contents = self.get_test_data_file_contents(
|
||||
"invoice.bpmn", "xml_with_entity"
|
||||
)
|
||||
file_contents = (
|
||||
file_contents.decode("utf-8")
|
||||
.replace("{{FULL_PATH_TO_FILE}}", tmp_file)
|
||||
.encode()
|
||||
)
|
||||
etree_element = SpecFileService.get_etree_from_xml_bytes(file_contents)
|
||||
assert string_replacement not in etree.tostring(etree_element)
|
||||
|
|
|
@ -87,7 +87,7 @@ jobs:
|
|||
run: ./bin/wait_for_frontend_to_be_up 5
|
||||
- name: wait_for_keycloak
|
||||
working-directory: ./spiffworkflow-backend
|
||||
run: ./bin/wait_for_keycloak 5
|
||||
run: ./keycloak/bin/wait_for_keycloak 5
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@v4
|
||||
with:
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { slowCypressDown } from 'cypress-slow-down';
|
||||
import { modifyProcessIdentifierForPathParam } from '../../src/helpers';
|
||||
import { miscDisplayName } from '../support/helpers';
|
||||
|
||||
// slowCypressDown(500);
|
||||
|
||||
describe('process-models', () => {
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
|
@ -132,7 +135,7 @@ describe('process-models', () => {
|
|||
cy.get('.tile-process-group-content-container').should('exist');
|
||||
});
|
||||
|
||||
it('can upload and run a bpmn file', () => {
|
||||
it.only('can upload and run a bpmn file', () => {
|
||||
const uuid = () => Cypress._.random(0, 1e6);
|
||||
const id = uuid();
|
||||
const directParentGroupId = 'acceptance-tests-group-one';
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
"bpmn-js-spiffworkflow": "sartography/bpmn-js-spiffworkflow#main",
|
||||
"cookie": "^0.5.0",
|
||||
"craco": "^0.0.3",
|
||||
"cypress-slow-down": "^1.2.1",
|
||||
"date-fns": "^2.28.0",
|
||||
"diagram-js": "^8.5.0",
|
||||
"dmn-js": "^12.2.0",
|
||||
|
@ -57,6 +58,7 @@
|
|||
"react-icons": "^4.4.0",
|
||||
"react-jsonschema-form": "^1.8.1",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-router": "^6.3.0",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"react-scripts": "^5.0.1",
|
||||
"remark-gfm": "^3.0.1",
|
||||
|
@ -9936,6 +9938,19 @@
|
|||
"node": "^14.0.0 || ^16.0.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cypress-plugin-config": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/cypress-plugin-config/-/cypress-plugin-config-1.2.0.tgz",
|
||||
"integrity": "sha512-vgMMwjeI/L+2xptqkyhJ20LRuZrrsdbPaGMNNLVq+Cwox5+9dm0E312gpMXgXRs05uyUAzL/nCm/tdTckSAgoQ=="
|
||||
},
|
||||
"node_modules/cypress-slow-down": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/cypress-slow-down/-/cypress-slow-down-1.2.1.tgz",
|
||||
"integrity": "sha512-Pd+nESR+Ca8I+mLGbBrPVMEFvJBWxkJcEdcIUDxSBnMoWI00hiIKxzEgVqCv5c6Oap2OPpnrPLbJBwveCNKLig==",
|
||||
"dependencies": {
|
||||
"cypress-plugin-config": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cypress/node_modules/@types/node": {
|
||||
"version": "14.18.26",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.26.tgz",
|
||||
|
@ -38782,6 +38797,19 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"cypress-plugin-config": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/cypress-plugin-config/-/cypress-plugin-config-1.2.0.tgz",
|
||||
"integrity": "sha512-vgMMwjeI/L+2xptqkyhJ20LRuZrrsdbPaGMNNLVq+Cwox5+9dm0E312gpMXgXRs05uyUAzL/nCm/tdTckSAgoQ=="
|
||||
},
|
||||
"cypress-slow-down": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/cypress-slow-down/-/cypress-slow-down-1.2.1.tgz",
|
||||
"integrity": "sha512-Pd+nESR+Ca8I+mLGbBrPVMEFvJBWxkJcEdcIUDxSBnMoWI00hiIKxzEgVqCv5c6Oap2OPpnrPLbJBwveCNKLig==",
|
||||
"requires": {
|
||||
"cypress-plugin-config": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"damerau-levenshtein": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
"bpmn-js-spiffworkflow": "sartography/bpmn-js-spiffworkflow#main",
|
||||
"cookie": "^0.5.0",
|
||||
"craco": "^0.0.3",
|
||||
"cypress-slow-down": "^1.2.1",
|
||||
"date-fns": "^2.28.0",
|
||||
"diagram-js": "^8.5.0",
|
||||
"dmn-js": "^12.2.0",
|
||||
|
@ -52,6 +53,7 @@
|
|||
"react-icons": "^4.4.0",
|
||||
"react-jsonschema-form": "^1.8.1",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-router": "^6.3.0",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"react-scripts": "^5.0.1",
|
||||
"remark-gfm": "^3.0.1",
|
||||
|
|
|
@ -84,6 +84,7 @@ type OwnProps = {
|
|||
onJsonFilesRequested?: (..._args: any[]) => any;
|
||||
onDmnFilesRequested?: (..._args: any[]) => any;
|
||||
onSearchProcessModels?: (..._args: any[]) => any;
|
||||
onElementsChanged?: (..._args: any[]) => any;
|
||||
url?: string;
|
||||
};
|
||||
|
||||
|
@ -109,6 +110,7 @@ export default function ReactDiagramEditor({
|
|||
onJsonFilesRequested,
|
||||
onDmnFilesRequested,
|
||||
onSearchProcessModels,
|
||||
onElementsChanged,
|
||||
url,
|
||||
}: OwnProps) {
|
||||
const [diagramXMLString, setDiagramXMLString] = useState('');
|
||||
|
@ -291,6 +293,11 @@ export default function ReactDiagramEditor({
|
|||
diagramModeler.on('element.click', (element: any) => {
|
||||
handleElementClick(element);
|
||||
});
|
||||
diagramModeler.on('elements.changed', (event: any) => {
|
||||
if (onElementsChanged) {
|
||||
onElementsChanged(event);
|
||||
}
|
||||
});
|
||||
|
||||
diagramModeler.on('spiff.service_tasks.requested', (event: any) => {
|
||||
handleServiceTasksRequested(event);
|
||||
|
@ -330,6 +337,7 @@ export default function ReactDiagramEditor({
|
|||
onJsonFilesRequested,
|
||||
onDmnFilesRequested,
|
||||
onSearchProcessModels,
|
||||
onElementsChanged,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* These hooks re-implement the now removed useBlocker and usePrompt hooks in 'react-router-dom'.
|
||||
* Thanks for the idea @piecyk https://github.com/remix-run/react-router/issues/8139#issuecomment-953816315
|
||||
* Source: https://github.com/remix-run/react-router/commit/256cad70d3fd4500b1abcfea66f3ee622fb90874#diff-b60f1a2d4276b2a605c05e19816634111de2e8a4186fe9dd7de8e344b65ed4d3L344-L381
|
||||
*/
|
||||
|
||||
import { useCallback, useContext, useEffect } from 'react';
|
||||
import { UNSAFE_NavigationContext as NavigationContext } from 'react-router-dom';
|
||||
|
||||
/**
|
||||
* Blocks all navigation attempts. This is useful for preventing the page from
|
||||
* changing until some condition is met, like saving form data.
|
||||
*
|
||||
* @param blocker
|
||||
* @param when
|
||||
* @see https://reactrouter.com/api/useBlocker
|
||||
*/
|
||||
export function useBlocker(blocker: any, when: any = true) {
|
||||
const { navigator } = useContext(NavigationContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (!when) return null;
|
||||
|
||||
const unblock = (navigator as any).block((tx: any) => {
|
||||
const autoUnblockingTx = {
|
||||
...tx,
|
||||
retry() {
|
||||
// Automatically unblock the transition so it can play all the way
|
||||
// through before retrying it. TODO: Figure out how to re-enable
|
||||
// this block if the transition is cancelled for some reason.
|
||||
unblock();
|
||||
tx.retry();
|
||||
},
|
||||
};
|
||||
|
||||
blocker(autoUnblockingTx);
|
||||
});
|
||||
|
||||
return unblock;
|
||||
}, [navigator, blocker, when]);
|
||||
}
|
||||
/**
|
||||
* Prompts the user with an Alert before they leave the current screen.
|
||||
*
|
||||
* @param message
|
||||
* @param when
|
||||
*/
|
||||
export function usePrompt(message: any, when: any = true) {
|
||||
const blocker = useCallback(
|
||||
(tx: any) => {
|
||||
// eslint-disable-next-line no-alert
|
||||
if (window.confirm(message)) tx.retry();
|
||||
},
|
||||
[message]
|
||||
);
|
||||
|
||||
useBlocker(blocker, when);
|
||||
}
|
|
@ -46,15 +46,21 @@ export default function ProcessInstanceLogList() {
|
|||
return (
|
||||
<tr key={rowToUse.id}>
|
||||
<td data-qa="paginated-entity-id">{rowToUse.id}</td>
|
||||
<td>{rowToUse.message}</td>
|
||||
<td>{rowToUse.bpmn_task_name}</td>
|
||||
<td>
|
||||
{rowToUse.bpmn_task_name ||
|
||||
(rowToUse.bpmn_task_type === 'Default Start Event'
|
||||
? 'Process Started'
|
||||
: '') ||
|
||||
(rowToUse.bpmn_task_type === 'End Event' ? 'Process Ended' : '')}
|
||||
</td>
|
||||
{isDetailedView && (
|
||||
<>
|
||||
<td>{rowToUse.message}</td>
|
||||
<td>{rowToUse.bpmn_task_identifier}</td>
|
||||
<td>{rowToUse.bpmn_task_type}</td>
|
||||
<td>{rowToUse.bpmn_process_identifier}</td>
|
||||
</>
|
||||
)}
|
||||
<td>{rowToUse.bpmn_process_identifier}</td>
|
||||
<td>{rowToUse.username}</td>
|
||||
<td>
|
||||
<Link
|
||||
|
@ -72,15 +78,15 @@ export default function ProcessInstanceLogList() {
|
|||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th>Message</th>
|
||||
<th>Task Name</th>
|
||||
{isDetailedView && (
|
||||
<>
|
||||
<th>Message</th>
|
||||
<th>Task Identifier</th>
|
||||
<th>Task Type</th>
|
||||
<th>Bpmn Process Identifier</th>
|
||||
</>
|
||||
)}
|
||||
<th>Bpmn Process Identifier</th>
|
||||
<th>User</th>
|
||||
<th>Timestamp</th>
|
||||
</tr>
|
||||
|
|
|
@ -35,11 +35,13 @@ import {
|
|||
} from '../interfaces';
|
||||
import ProcessSearch from '../components/ProcessSearch';
|
||||
import { Notification } from '../components/Notification';
|
||||
import { usePrompt } from '../hooks/UsePrompt';
|
||||
|
||||
export default function ProcessModelEditDiagram() {
|
||||
const [showFileNameEditor, setShowFileNameEditor] = useState(false);
|
||||
const handleShowFileNameEditor = () => setShowFileNameEditor(true);
|
||||
const [processModel, setProcessModel] = useState<ProcessModel | null>(null);
|
||||
const [diagramHasChanges, setDiagramHasChanges] = useState<boolean>(false);
|
||||
|
||||
const [scriptText, setScriptText] = useState<string>('');
|
||||
const [scriptType, setScriptType] = useState<string>('');
|
||||
|
@ -112,6 +114,8 @@ export default function ProcessModelEditDiagram() {
|
|||
|
||||
const processModelPath = `process-models/${modifiedProcessModelId}`;
|
||||
|
||||
usePrompt('Changes you made may not be saved.', diagramHasChanges);
|
||||
|
||||
useEffect(() => {
|
||||
// Grab all available process models in case we need to search for them.
|
||||
// Taken from the Process Group List
|
||||
|
@ -206,6 +210,11 @@ export default function ProcessModelEditDiagram() {
|
|||
// after saving the file, make sure we null out newFileName
|
||||
// so it does not get used over the params
|
||||
setNewFileName('');
|
||||
setDiagramHasChanges(false);
|
||||
};
|
||||
|
||||
const onElementsChanged = () => {
|
||||
setDiagramHasChanges(true);
|
||||
};
|
||||
|
||||
const onDeleteFile = (fileName = params.file_name) => {
|
||||
|
@ -922,6 +931,7 @@ export default function ProcessModelEditDiagram() {
|
|||
onLaunchDmnEditor={onLaunchDmnEditor}
|
||||
onDmnFilesRequested={onDmnFilesRequested}
|
||||
onSearchProcessModels={onSearchProcessModels}
|
||||
onElementsChanged={onElementsChanged}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue