From f2ca47e79873202a07a7673bdf06355b56c4d9e9 Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 17 Feb 2023 13:08:45 -0500 Subject: [PATCH 01/41] bump spiffworkflow hash --- spiffworkflow-backend/poetry.lock | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/spiffworkflow-backend/poetry.lock b/spiffworkflow-backend/poetry.lock index 181f510c7..a1df93676 100644 --- a/spiffworkflow-backend/poetry.lock +++ b/spiffworkflow-backend/poetry.lock @@ -1825,7 +1825,7 @@ lxml = "*" type = "git" url = "https://github.com/sartography/SpiffWorkflow" reference = "main" -resolved_reference = "76ecbf7cc8d47185fa410f301ffa3452079ee672" +resolved_reference = "b439f69f23b547df4de1e8e0c636997f2fd4e33b" [[package]] name = "SQLAlchemy" @@ -2658,7 +2658,6 @@ lazy-object-proxy = [ {file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"}, ] livereload = [ - {file = "livereload-2.6.3-py2.py3-none-any.whl", hash = "sha256:ad4ac6f53b2d62bb6ce1a5e6e96f1f00976a32348afedcb4b6d68df2a1d346e4"}, {file = "livereload-2.6.3.tar.gz", hash = "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"}, ] lxml = [ @@ -2867,10 +2866,7 @@ 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"}, @@ -3205,7 +3201,6 @@ ruamel-yaml-clib = [ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:d000f258cf42fec2b1bbf2863c61d7b8918d31ffee905da62dede869254d3b8a"}, {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:045e0626baf1c52e5527bd5db361bc83180faaba2ff586e763d3d5982a876a9e"}, {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_12_6_arm64.whl", hash = "sha256:721bc4ba4525f53f6a611ec0967bdcee61b31df5a56801281027a3a6d1c2daf5"}, - {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:41d0f1fa4c6830176eef5b276af04c89320ea616655d01327d5ce65e50575c94"}, {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4b3a93bb9bc662fc1f99c5c3ea8e623d8b23ad22f861eb6fce9377ac07ad6072"}, {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_12_0_arm64.whl", hash = "sha256:a234a20ae07e8469da311e182e70ef6b199d0fbeb6c6cc2901204dd87fb867e8"}, {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:15910ef4f3e537eea7fe45f8a5d19997479940d9196f357152a09031c5be59f3"}, From 4c46104202705045fc7632bcd89e8a735086dd70 Mon Sep 17 00:00:00 2001 From: jasquat Date: Fri, 17 Feb 2023 14:35:13 -0500 Subject: [PATCH 02/41] added ability to display the environment in the frontend header bar w/ burnettk --- .../src/components/NavigationBar.tsx | 8 ++++- spiffworkflow-frontend/src/config.tsx | 29 +++++++++++++++---- spiffworkflow-frontend/src/index.css | 15 ++++++++++ 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/spiffworkflow-frontend/src/components/NavigationBar.tsx b/spiffworkflow-frontend/src/components/NavigationBar.tsx index e482ae526..b1ed09a4c 100644 --- a/spiffworkflow-frontend/src/components/NavigationBar.tsx +++ b/spiffworkflow-frontend/src/components/NavigationBar.tsx @@ -25,6 +25,7 @@ import { useUriListForPermissions } from '../hooks/UriListForPermissions'; import { PermissionsToCheck } from '../interfaces'; import { usePermissionFetcher } from '../hooks/PermissionService'; import { UnauthenticatedError } from '../services/HttpService'; +import { SPIFF_ENVIRONMENT } from '../config'; // for ref: https://react-bootstrap.github.io/components/navbar/ export default function NavigationBar() { @@ -80,7 +81,12 @@ export default function NavigationBar() { if (UserService.isLoggedIn()) { return ( <> - + {SPIFF_ENVIRONMENT ? ( + + {SPIFF_ENVIRONMENT} + + ) : null} + {UserService.getPreferredUsername()} Date: Mon, 20 Feb 2023 12:43:06 +0100 Subject: [PATCH 03/41] backend/git_service: check repo URLs from webhook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we are cloning a private repo we are using `ssh_url` in our case. Signed-off-by: Jakub Sokołowski --- .../spiffworkflow_backend/services/git_service.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py index cf308ef6c..16c064d18 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py @@ -197,14 +197,13 @@ class GitService: f" body: {webhook}" ) - clone_url = webhook["repository"]["clone_url"] - if ( - clone_url - != current_app.config["SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL"] - ): + config_clone_url = current_app.config["SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL"] + repo = webhook["repository"] + valid_clone_urls = [repo["clone_url"], repo["git_url"], repo["ssh_url"]] + if config_clone_url not in valid_clone_urls: raise GitCloneUrlMismatchError( - "Configured clone url does not match clone url from webhook:" - f" {clone_url}" + "Configured clone url does not match the repo URLs from webhook: %s =/= %s" + % (config_clone_url, valid_clone_urls) ) if "ref" not in webhook: From fb024a49f7d4118f233bedadde75942aecdac0bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Soko=C5=82owski?= Date: Mon, 20 Feb 2023 13:10:58 +0100 Subject: [PATCH 04/41] backend/git_service: accept webhook test requests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://docs.github.com/en/webhooks-and-events/webhooks/testing-webhooks Signed-off-by: Jakub Sokołowski --- .../src/spiffworkflow_backend/services/git_service.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py index 16c064d18..e73dd0612 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py @@ -206,6 +206,10 @@ class GitService: % (config_clone_url, valid_clone_urls) ) + # Test webhook requests have a zen koan and hook info. + if "zen" in webhook or "hook_id" in webhook: + return False + if "ref" not in webhook: raise InvalidGitWebhookBodyError( f"Could not find the 'ref' arg in the webhook boy: {webhook}" From a600736e67a823c6aba85be93d714b4252698d56 Mon Sep 17 00:00:00 2001 From: burnettk Date: Mon, 20 Feb 2023 10:58:04 -0500 Subject: [PATCH 05/41] delint --- .../src/spiffworkflow_backend/services/git_service.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py index e73dd0612..f8ea457d3 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py @@ -197,13 +197,15 @@ class GitService: f" body: {webhook}" ) - config_clone_url = current_app.config["SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL"] + config_clone_url = current_app.config[ + "SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL" + ] repo = webhook["repository"] valid_clone_urls = [repo["clone_url"], repo["git_url"], repo["ssh_url"]] if config_clone_url not in valid_clone_urls: raise GitCloneUrlMismatchError( - "Configured clone url does not match the repo URLs from webhook: %s =/= %s" - % (config_clone_url, valid_clone_urls) + "Configured clone url does not match the repo URLs from webhook: %s" + " =/= %s" % (config_clone_url, valid_clone_urls) ) # Test webhook requests have a zen koan and hook info. From 01a95011ad032c520475f0b4a5b0dc79eb778905 Mon Sep 17 00:00:00 2001 From: jbirddog <100367399+jbirddog@users.noreply.github.com> Date: Mon, 20 Feb 2023 18:12:50 -0500 Subject: [PATCH 06/41] Look in task data/script engine environment for data, not just workflow data. (#143) --- .../routes/process_api_blueprint.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py index d50255a87..1274e465d 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -94,9 +94,11 @@ def _process_data_fetcher( process_instance = _find_process_instance_by_id_or_raise(process_instance_id) processor = ProcessInstanceProcessor(process_instance) all_process_data = processor.get_data() - process_data_value = None - if process_data_identifier in all_process_data: - process_data_value = all_process_data[process_data_identifier] + process_data_value = all_process_data.get(process_data_identifier) + + if process_data_value is None: + script_engine_last_result = processor._script_engine.environment.last_result() + process_data_value = script_engine_last_result.get(process_data_identifier) if process_data_value is not None and index is not None: process_data_value = process_data_value[index] @@ -108,7 +110,7 @@ def _process_data_fetcher( ): parts = process_data_value.split(";") mimetype = parts[0][4:] - filename = parts[1] + filename = parts[1].split("=")[1] base64_value = parts[2].split(",")[1] file_contents = base64.b64decode(base64_value) From 2d76a3936505cd091d948984d691a129d4c736e9 Mon Sep 17 00:00:00 2001 From: jasquat Date: Tue, 21 Feb 2023 12:43:08 -0500 Subject: [PATCH 07/41] adding some padding to form text inputs w/ burnettk --- .../src/themes/carbon/BaseInputTemplate/BaseInputTemplate.tsx | 2 +- .../src/themes/carbon/TextareaWidget/TextareaWidget.tsx | 2 +- spiffworkflow-frontend/src/themes/carbon/index.css | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/spiffworkflow-frontend/src/themes/carbon/BaseInputTemplate/BaseInputTemplate.tsx b/spiffworkflow-frontend/src/themes/carbon/BaseInputTemplate/BaseInputTemplate.tsx index 699ffeb90..81cb5e890 100644 --- a/spiffworkflow-frontend/src/themes/carbon/BaseInputTemplate/BaseInputTemplate.tsx +++ b/spiffworkflow-frontend/src/themes/carbon/BaseInputTemplate/BaseInputTemplate.tsx @@ -106,7 +106,7 @@ export default function BaseInputTemplate< Date: Mon, 20 Feb 2023 22:21:31 +0100 Subject: [PATCH 08/41] backend: fix use of SSH private key for git ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Primarily this is supposed to fix the `git pull` aciton triggered by webhooks from GitHub. But in addition to that the point is to simplify that committing wrapper which has far too much in it. Instead of passing everything as CLI arguments one should make use of already supported environment variables and the `env` argument to `subprocess` functions like `run()`. Writing extra logic in the wrapper only makes it unnecessarily complicated. By passing both user, email, and the SSH options in `run_shell_command` we avoid the need to repeat the same boilerplate to provide Git config and SSH credentials. Signed-off-by: Jakub Sokołowski --- .../bin/git_commit_bpmn_models_repo | 44 ++++--------------- .../spiffworkflow_backend/config/default.py | 10 +---- .../services/git_service.py | 37 ++++++---------- 3 files changed, 24 insertions(+), 67 deletions(-) diff --git a/spiffworkflow-backend/bin/git_commit_bpmn_models_repo b/spiffworkflow-backend/bin/git_commit_bpmn_models_repo index b475427a7..8e9276eea 100755 --- a/spiffworkflow-backend/bin/git_commit_bpmn_models_repo +++ b/spiffworkflow-backend/bin/git_commit_bpmn_models_repo @@ -12,17 +12,9 @@ set -o errtrace -o errexit -o nounset -o pipefail bpmn_models_absolute_dir="$1" git_commit_message="$2" git_branch="$3" -git_commit_username="$4" -git_commit_email="$5" -git_commit_password="$6" -if [[ -z "${5:-}" ]]; then - >&2 echo "usage: $(basename "$0") [bpmn_models_absolute_dir] [git_commit_message] [git_branch] [git_commit_username] [git_commit_email]" - exit 1 -fi - -if [[ -z "$git_commit_password" && -z "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY:-}" ]]; then - >&2 echo "ERROR: A git password or SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY must be provided" +if [[ -z "${3:-}" ]]; then + >&2 echo "usage: $(basename "${0}") [bpmn_models_absolute_dir] [git_commit_message] [git_branch]" exit 1 fi @@ -32,38 +24,20 @@ function failed_to_get_lock() { } function run() { - cd "$bpmn_models_absolute_dir" + cd "${bpmn_models_absolute_dir}" git add . # https://unix.stackexchange.com/a/155077/456630 if [ -z "$(git status --porcelain)" ]; then echo "No changes to commit" - else - - git config --local user.name "$git_commit_username" - git config --local user.email "$git_commit_email" - - if [[ -n "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY:-}" ]]; then - tmpfile=$(mktemp /tmp/tmp_git.XXXXXX) - chmod 600 "$tmpfile" - echo "$SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY" >"$tmpfile" - export GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i ${tmpfile} -F /dev/null" - else - PAT="${git_commit_username}:${git_commit_password}" - AUTH=$(echo -n "$PAT" | openssl base64 | tr -d '\n') - git config --local http.extraHeader "Authorization: Basic $AUTH" - fi - - git commit -m "$git_commit_message" - git push --set-upstream origin "$git_branch" - - if [[ -z "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY:-}" ]]; then - git config --unset --local http.extraHeader - fi + return fi + + git commit -m "${git_commit_message}" + git push --set-upstream origin "${git_branch}" } exec {lock_fd}>/var/lock/mylockfile || failed_to_get_lock -flock --timeout 60 "$lock_fd" || failed_to_get_lock +flock --timeout 60 "${lock_fd}" || failed_to_get_lock run -flock -u "$lock_fd" +flock -u "${lock_fd}" diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py b/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py index c6994a7cf..d16dcd916 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py @@ -96,9 +96,6 @@ SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL = environ.get( SPIFFWORKFLOW_BACKEND_GIT_COMMIT_ON_SAVE = ( environ.get("SPIFFWORKFLOW_BACKEND_GIT_COMMIT_ON_SAVE", default="false") == "true" ) -SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY = environ.get( - "SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY" -) SPIFFWORKFLOW_BACKEND_GIT_USERNAME = environ.get("SPIFFWORKFLOW_BACKEND_GIT_USERNAME") SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL = environ.get( "SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL" @@ -106,11 +103,8 @@ SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL = environ.get( SPIFFWORKFLOW_BACKEND_GITHUB_WEBHOOK_SECRET = environ.get( "SPIFFWORKFLOW_BACKEND_GITHUB_WEBHOOK_SECRET", default=None ) -SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY = environ.get( - "SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY", default=None -) -SPIFFWORKFLOW_BACKEND_GIT_USER_PASSWORD = environ.get( - "SPIFFWORKFLOW_BACKEND_GIT_USER_PASSWORD", default=None +SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH", default=None ) # Database Configuration diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py index f8ea457d3..e6d924264 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py @@ -94,19 +94,7 @@ class GitService: raise ConfigurationError( "SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR config must be set" ) - if current_app.config["SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY"]: - os.environ["SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY"] = ( - current_app.config["SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY"] - ) - git_username = "" - git_email = "" - if ( - current_app.config["SPIFFWORKFLOW_BACKEND_GIT_USERNAME"] - and current_app.config["SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL"] - ): - git_username = current_app.config["SPIFFWORKFLOW_BACKEND_GIT_USERNAME"] - git_email = current_app.config["SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL"] shell_command_path = os.path.join( current_app.root_path, "..", "..", "bin", "git_commit_bpmn_models_repo" ) @@ -115,9 +103,6 @@ class GitService: repo_path_to_use, message, branch_name_to_use, - git_username, - git_email, - current_app.config["SPIFFWORKFLOW_BACKEND_GIT_USER_PASSWORD"], ] return cls.run_shell_command_to_get_stdout(shell_command) @@ -169,8 +154,17 @@ class GitService: cls, command: list[str], return_success_state: bool = False ) -> Union[subprocess.CompletedProcess[bytes], bool]: """Run_shell_command.""" + env = { + 'GIT_COMMITTER_NAME': current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USERNAME", "unknown"), + 'GIT_COMMITTER_EMAIL': current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL", "unknown@example.org"), + } + # SSH authentication can be also provided via gitconfig. + ssh_key_path = current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH") + if ssh_key_path is not None: + env['GIT_SSH_COMMAND'] = 'ssh -F /dev/null -i %s' % ssh_key_path + # this is fine since we pass the commands directly - result = subprocess.run(command, check=False, capture_output=True) # noqa + result = subprocess.run(command, check=False, capture_output=True, env=env) # noqa if return_success_state: return result.returncode == 0 @@ -178,9 +172,9 @@ class GitService: stdout = result.stdout.decode("utf-8") stderr = result.stderr.decode("utf-8") raise GitCommandError( - f"Failed to execute git command: {command} " - f"Stdout: {stdout} " - f"Stderr: {stderr} " + f"Failed to execute git command: {command}" + f"Stdout: {stdout}" + f"Stderr: {stderr}" ) return result @@ -252,11 +246,6 @@ class GitService: git_clone_url = current_app.config[ "SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL" ] - if git_clone_url.startswith("https://"): - git_clone_url = git_clone_url.replace( - "https://", - f"https://{current_app.config['SPIFFWORKFLOW_BACKEND_GIT_USERNAME']}:{current_app.config['SPIFFWORKFLOW_BACKEND_GIT_USER_PASSWORD']}@", - ) cmd = ["git", "clone", git_clone_url, destination_process_root] cls.run_shell_command(cmd) From 1bbf3a264cddb92ff24e5623a8a8aa0e32c90dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Soko=C5=82owski?= Date: Mon, 20 Feb 2023 22:27:18 +0100 Subject: [PATCH 09/41] backend: specify --rebase when using git pull MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise it fails with: ``` Pulling without specifying how to reconcile divergent branches is discouraged. ``` Signed-off-by: Jakub Sokołowski --- .../src/spiffworkflow_backend/services/git_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py index e6d924264..0638cca9d 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py @@ -225,7 +225,7 @@ class GitService: with FileSystemService.cd( current_app.config["SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR"] ): - cls.run_shell_command(["git", "pull"]) + cls.run_shell_command(["git", "pull", "--rebase"]) return True @classmethod From 56a913e33ca9834166208bad64145334fa9df638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Soko=C5=82owski?= Date: Mon, 20 Feb 2023 22:28:35 +0100 Subject: [PATCH 10/41] backend: use sensible lock filename for git MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Sokołowski --- spiffworkflow-backend/bin/git_commit_bpmn_models_repo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spiffworkflow-backend/bin/git_commit_bpmn_models_repo b/spiffworkflow-backend/bin/git_commit_bpmn_models_repo index 8e9276eea..215e0ac9d 100755 --- a/spiffworkflow-backend/bin/git_commit_bpmn_models_repo +++ b/spiffworkflow-backend/bin/git_commit_bpmn_models_repo @@ -37,7 +37,7 @@ function run() { git push --set-upstream origin "${git_branch}" } -exec {lock_fd}>/var/lock/mylockfile || failed_to_get_lock +exec {lock_fd}>/var/lock/spiff-workflow-git-lock || failed_to_get_lock flock --timeout 60 "${lock_fd}" || failed_to_get_lock run flock -u "${lock_fd}" From 819415d487299cef433e678012f2a3d76cd0963b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Soko=C5=82owski?= Date: Tue, 21 Feb 2023 20:02:16 +0100 Subject: [PATCH 11/41] backend: create SSH key file when contents provided MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Sokołowski --- spiffworkflow-backend/bin/boot_server_in_docker | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spiffworkflow-backend/bin/boot_server_in_docker b/spiffworkflow-backend/bin/boot_server_in_docker index 2976e27d8..4ab98e324 100755 --- a/spiffworkflow-backend/bin/boot_server_in_docker +++ b/spiffworkflow-backend/bin/boot_server_in_docker @@ -55,6 +55,14 @@ if [[ "${SPIFFWORKFLOW_BACKEND_RUN_DATA_SETUP:-}" != "false" ]]; then SPIFFWORKFLOW_BACKEND_FAIL_ON_INVALID_PROCESS_MODELS=false poetry run python bin/save_all_bpmn.py fi +if [[ -n "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY:-}" ]]; then + if [[ -z "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH}" ]]; then + export SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH=$(mktemp /tmp/ssh_private_key.XXXXXX) + fi + chmod 600 "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH}" + echo "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY}" >"${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH}" +fi + # Assure that the the Process Models Directory is initialized as a git repo git init "${SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR}" git config --global --add safe.directory "${SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR}" From b0d132fc1e6e1a21f49d8ac422e957ad017eb49d Mon Sep 17 00:00:00 2001 From: jasquat Date: Tue, 21 Feb 2023 15:08:19 -0500 Subject: [PATCH 12/41] give access to download process data files if a user has access to start a process model w/ burnettk --- .../services/authorization_service.py | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/authorization_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/authorization_service.py index 9db4c39c6..3a054ec6b 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/authorization_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/authorization_service.py @@ -76,8 +76,9 @@ PATH_SEGMENTS_FOR_PERMISSION_ALL = [ }, {"path": "/process-instance-suspend", "relevant_permissions": ["create"]}, {"path": "/process-instance-terminate", "relevant_permissions": ["create"]}, - {"path": "/task-data", "relevant_permissions": ["read", "update"]}, {"path": "/process-data", "relevant_permissions": ["read"]}, + {"path": "/process-data-file-download", "relevant_permissions": ["read"]}, + {"path": "/task-data", "relevant_permissions": ["read", "update"]}, ] @@ -567,15 +568,24 @@ class AuthorizationService: permissions_to_assign.append( PermissionToAssign(permission="create", target_uri=target_uri) ) - target_uri = f"/process-instances/for-me/{process_related_path_segment}" - permissions_to_assign.append( - PermissionToAssign(permission="read", target_uri=target_uri) - ) - target_uri = f"/logs/{process_related_path_segment}" - permissions_to_assign.append( - PermissionToAssign(permission="read", target_uri=target_uri) - ) + # giving people access to all logs for an instance actually gives them a little bit more access + # than would be optimal. ideally, you would only be able to view the logs for instances that you started + # or that you need to approve, etc. we could potentially implement this by adding before filters + # in the controllers that confirm that you are viewing logs for your instances. i guess you need to check + # both for-me and NOT for-me URLs for the instance in question to see if you should get access to its logs. + # if we implemented things this way, there would also be no way to restrict access to logs when you do not + # restrict access to instances. everything would be inheriting permissions from instances. + # if we want to really codify this rule, we could change logs from a prefix to a suffix (just add it to the end of the process instances path). + # but that makes it harder to change our minds in the future. + for target_uri in [ + f"/process-instances/for-me/{process_related_path_segment}", + f"/logs/{process_related_path_segment}", + f"/process-data-file-download/{process_related_path_segment}", + ]: + permissions_to_assign.append( + PermissionToAssign(permission="read", target_uri=target_uri) + ) else: if permission_set == "all": for path_segment_dict in PATH_SEGMENTS_FOR_PERMISSION_ALL: From e5b83d091978ddad484fd20526ad0c575c8ab06d Mon Sep 17 00:00:00 2001 From: jasquat Date: Tue, 21 Feb 2023 15:28:54 -0500 Subject: [PATCH 13/41] fixed tests w/ burnettk --- .../services/authorization_service.py | 3 ++- .../services/git_service.py | 16 ++++++++++------ .../scripts/test_get_all_permissions.py | 1 + .../unit/test_authorization_service.py | 18 ++++++++++++++---- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/authorization_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/authorization_service.py index 3a054ec6b..9d2f80cb4 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/authorization_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/authorization_service.py @@ -576,7 +576,8 @@ class AuthorizationService: # both for-me and NOT for-me URLs for the instance in question to see if you should get access to its logs. # if we implemented things this way, there would also be no way to restrict access to logs when you do not # restrict access to instances. everything would be inheriting permissions from instances. - # if we want to really codify this rule, we could change logs from a prefix to a suffix (just add it to the end of the process instances path). + # if we want to really codify this rule, we could change logs from a prefix to a suffix + # (just add it to the end of the process instances path). # but that makes it harder to change our minds in the future. for target_uri in [ f"/process-instances/for-me/{process_related_path_segment}", diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py index 0638cca9d..d885e4b69 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py @@ -154,17 +154,21 @@ class GitService: cls, command: list[str], return_success_state: bool = False ) -> Union[subprocess.CompletedProcess[bytes], bool]: """Run_shell_command.""" - env = { - 'GIT_COMMITTER_NAME': current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USERNAME", "unknown"), - 'GIT_COMMITTER_EMAIL': current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL", "unknown@example.org"), + git_env_options = { + "GIT_COMMITTER_NAME": current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USERNAME") or 'unknown', + "GIT_COMMITTER_EMAIL": current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL") or "unknown@example.org", } # SSH authentication can be also provided via gitconfig. - ssh_key_path = current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH") + ssh_key_path = current_app.config.get( + "SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH" + ) if ssh_key_path is not None: - env['GIT_SSH_COMMAND'] = 'ssh -F /dev/null -i %s' % ssh_key_path + git_env_options["GIT_SSH_COMMAND"] = "ssh -F /dev/null -i %s" % ssh_key_path # this is fine since we pass the commands directly - result = subprocess.run(command, check=False, capture_output=True, env=env) # noqa + result = subprocess.run( # noqa + command, check=False, capture_output=True, env=git_env_options + ) if return_success_state: return result.returncode == 0 diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_all_permissions.py b/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_all_permissions.py index 95d15fbf8..928299d4f 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_all_permissions.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_all_permissions.py @@ -61,6 +61,7 @@ class TestGetAllPermissions(BaseTest): "uri": "/tasks", "permissions": ["create", "read", "update", "delete"], }, + {'group_identifier': 'my_test_group', 'uri': '/process-data-file-download/hey:group:*', 'permissions': ['read']} ] permissions = GetAllPermissions().run(script_attributes_context) diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_authorization_service.py b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_authorization_service.py index d414616c5..ea1978efc 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_authorization_service.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_authorization_service.py @@ -156,9 +156,10 @@ class TestAuthorizationService(BaseTest): with_db_and_bpmn_file_cleanup: None, ) -> None: """Test_explode_permissions_all_on_process_group.""" - expected_permissions = [ + expected_permissions = sorted([ ("/logs/some-process-group:some-process-model:*", "read"), ("/process-data/some-process-group:some-process-model:*", "read"), + ("/process-data-file-download/some-process-group:some-process-model:*", "read"), ("/process-groups/some-process-group:some-process-model:*", "create"), ("/process-groups/some-process-group:some-process-model:*", "delete"), ("/process-groups/some-process-group:some-process-model:*", "read"), @@ -180,7 +181,7 @@ class TestAuthorizationService(BaseTest): ("/process-models/some-process-group:some-process-model:*", "update"), ("/task-data/some-process-group:some-process-model:*", "read"), ("/task-data/some-process-group:some-process-model:*", "update"), - ] + ]) permissions_to_assign = AuthorizationService.explode_permissions( "all", "PG:/some-process-group/some-process-model" ) @@ -201,6 +202,10 @@ class TestAuthorizationService(BaseTest): "/logs/some-process-group:some-process-model:*", "read", ), + ( + "/process-data-file-download/some-process-group:some-process-model:*", + "read", + ), ( "/process-instances/for-me/some-process-group:some-process-model:*", "read", @@ -222,8 +227,9 @@ class TestAuthorizationService(BaseTest): with_db_and_bpmn_file_cleanup: None, ) -> None: """Test_explode_permissions_all_on_process_model.""" - expected_permissions = [ + expected_permissions = sorted([ ("/logs/some-process-group:some-process-model/*", "read"), + ("/process-data-file-download/some-process-group:some-process-model/*", "read"), ("/process-data/some-process-group:some-process-model/*", "read"), ( "/process-instance-suspend/some-process-group:some-process-model/*", @@ -242,7 +248,7 @@ class TestAuthorizationService(BaseTest): ("/process-models/some-process-group:some-process-model/*", "update"), ("/task-data/some-process-group:some-process-model/*", "read"), ("/task-data/some-process-group:some-process-model/*", "update"), - ] + ]) permissions_to_assign = AuthorizationService.explode_permissions( "all", "PM:/some-process-group/some-process-model" ) @@ -263,6 +269,10 @@ class TestAuthorizationService(BaseTest): "/logs/some-process-group:some-process-model/*", "read", ), + ( + "/process-data-file-download/some-process-group:some-process-model/*", + "read", + ), ( "/process-instances/for-me/some-process-group:some-process-model/*", "read", From c5d611f03b44e18a8df786eae00796821b944e2b Mon Sep 17 00:00:00 2001 From: jasquat Date: Tue, 21 Feb 2023 16:42:11 -0500 Subject: [PATCH 14/41] disable strict host checking for git commands w/ burnettk --- .../services/git_service.py | 14 ++- .../scripts/test_get_all_permissions.py | 6 +- .../unit/test_authorization_service.py | 118 +++++++++++------- 3 files changed, 86 insertions(+), 52 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py index d885e4b69..ba4755f28 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py @@ -155,15 +155,23 @@ class GitService: ) -> Union[subprocess.CompletedProcess[bytes], bool]: """Run_shell_command.""" git_env_options = { - "GIT_COMMITTER_NAME": current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USERNAME") or 'unknown', - "GIT_COMMITTER_EMAIL": current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL") or "unknown@example.org", + "GIT_COMMITTER_NAME": ( + current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USERNAME") + or "unknown" + ), + "GIT_COMMITTER_EMAIL": ( + current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL") + or "unknown@example.org" + ), } # SSH authentication can be also provided via gitconfig. ssh_key_path = current_app.config.get( "SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH" ) if ssh_key_path is not None: - git_env_options["GIT_SSH_COMMAND"] = "ssh -F /dev/null -i %s" % ssh_key_path + git_env_options["GIT_SSH_COMMAND"] = ( + "ssh -F /dev/null -o StrictHostKeyChecking=no -i %s" % ssh_key_path + ) # this is fine since we pass the commands directly result = subprocess.run( # noqa diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_all_permissions.py b/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_all_permissions.py index 928299d4f..9dd416fce 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_all_permissions.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_all_permissions.py @@ -61,7 +61,11 @@ class TestGetAllPermissions(BaseTest): "uri": "/tasks", "permissions": ["create", "read", "update", "delete"], }, - {'group_identifier': 'my_test_group', 'uri': '/process-data-file-download/hey:group:*', 'permissions': ['read']} + { + "group_identifier": "my_test_group", + "uri": "/process-data-file-download/hey:group:*", + "permissions": ["read"], + }, ] permissions = GetAllPermissions().run(script_attributes_context) diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_authorization_service.py b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_authorization_service.py index ea1978efc..01b1cc3fd 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_authorization_service.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_authorization_service.py @@ -156,32 +156,43 @@ class TestAuthorizationService(BaseTest): with_db_and_bpmn_file_cleanup: None, ) -> None: """Test_explode_permissions_all_on_process_group.""" - expected_permissions = sorted([ - ("/logs/some-process-group:some-process-model:*", "read"), - ("/process-data/some-process-group:some-process-model:*", "read"), - ("/process-data-file-download/some-process-group:some-process-model:*", "read"), - ("/process-groups/some-process-group:some-process-model:*", "create"), - ("/process-groups/some-process-group:some-process-model:*", "delete"), - ("/process-groups/some-process-group:some-process-model:*", "read"), - ("/process-groups/some-process-group:some-process-model:*", "update"), - ( - "/process-instance-suspend/some-process-group:some-process-model:*", - "create", - ), - ( - "/process-instance-terminate/some-process-group:some-process-model:*", - "create", - ), - ("/process-instances/some-process-group:some-process-model:*", "create"), - ("/process-instances/some-process-group:some-process-model:*", "delete"), - ("/process-instances/some-process-group:some-process-model:*", "read"), - ("/process-models/some-process-group:some-process-model:*", "create"), - ("/process-models/some-process-group:some-process-model:*", "delete"), - ("/process-models/some-process-group:some-process-model:*", "read"), - ("/process-models/some-process-group:some-process-model:*", "update"), - ("/task-data/some-process-group:some-process-model:*", "read"), - ("/task-data/some-process-group:some-process-model:*", "update"), - ]) + expected_permissions = sorted( + [ + ("/logs/some-process-group:some-process-model:*", "read"), + ("/process-data/some-process-group:some-process-model:*", "read"), + ( + "/process-data-file-download/some-process-group:some-process-model:*", + "read", + ), + ("/process-groups/some-process-group:some-process-model:*", "create"), + ("/process-groups/some-process-group:some-process-model:*", "delete"), + ("/process-groups/some-process-group:some-process-model:*", "read"), + ("/process-groups/some-process-group:some-process-model:*", "update"), + ( + "/process-instance-suspend/some-process-group:some-process-model:*", + "create", + ), + ( + "/process-instance-terminate/some-process-group:some-process-model:*", + "create", + ), + ( + "/process-instances/some-process-group:some-process-model:*", + "create", + ), + ( + "/process-instances/some-process-group:some-process-model:*", + "delete", + ), + ("/process-instances/some-process-group:some-process-model:*", "read"), + ("/process-models/some-process-group:some-process-model:*", "create"), + ("/process-models/some-process-group:some-process-model:*", "delete"), + ("/process-models/some-process-group:some-process-model:*", "read"), + ("/process-models/some-process-group:some-process-model:*", "update"), + ("/task-data/some-process-group:some-process-model:*", "read"), + ("/task-data/some-process-group:some-process-model:*", "update"), + ] + ) permissions_to_assign = AuthorizationService.explode_permissions( "all", "PG:/some-process-group/some-process-model" ) @@ -227,28 +238,39 @@ class TestAuthorizationService(BaseTest): with_db_and_bpmn_file_cleanup: None, ) -> None: """Test_explode_permissions_all_on_process_model.""" - expected_permissions = sorted([ - ("/logs/some-process-group:some-process-model/*", "read"), - ("/process-data-file-download/some-process-group:some-process-model/*", "read"), - ("/process-data/some-process-group:some-process-model/*", "read"), - ( - "/process-instance-suspend/some-process-group:some-process-model/*", - "create", - ), - ( - "/process-instance-terminate/some-process-group:some-process-model/*", - "create", - ), - ("/process-instances/some-process-group:some-process-model/*", "create"), - ("/process-instances/some-process-group:some-process-model/*", "delete"), - ("/process-instances/some-process-group:some-process-model/*", "read"), - ("/process-models/some-process-group:some-process-model/*", "create"), - ("/process-models/some-process-group:some-process-model/*", "delete"), - ("/process-models/some-process-group:some-process-model/*", "read"), - ("/process-models/some-process-group:some-process-model/*", "update"), - ("/task-data/some-process-group:some-process-model/*", "read"), - ("/task-data/some-process-group:some-process-model/*", "update"), - ]) + expected_permissions = sorted( + [ + ("/logs/some-process-group:some-process-model/*", "read"), + ( + "/process-data-file-download/some-process-group:some-process-model/*", + "read", + ), + ("/process-data/some-process-group:some-process-model/*", "read"), + ( + "/process-instance-suspend/some-process-group:some-process-model/*", + "create", + ), + ( + "/process-instance-terminate/some-process-group:some-process-model/*", + "create", + ), + ( + "/process-instances/some-process-group:some-process-model/*", + "create", + ), + ( + "/process-instances/some-process-group:some-process-model/*", + "delete", + ), + ("/process-instances/some-process-group:some-process-model/*", "read"), + ("/process-models/some-process-group:some-process-model/*", "create"), + ("/process-models/some-process-group:some-process-model/*", "delete"), + ("/process-models/some-process-group:some-process-model/*", "read"), + ("/process-models/some-process-group:some-process-model/*", "update"), + ("/task-data/some-process-group:some-process-model/*", "read"), + ("/task-data/some-process-group:some-process-model/*", "update"), + ] + ) permissions_to_assign = AuthorizationService.explode_permissions( "all", "PM:/some-process-group/some-process-model" ) From 90de749ab970b511f063c96a197120fad0bd36ec Mon Sep 17 00:00:00 2001 From: jasquat Date: Tue, 21 Feb 2023 16:43:52 -0500 Subject: [PATCH 15/41] more git config updates w/ burnettk --- .../src/spiffworkflow_backend/services/git_service.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py index ba4755f28..f7baba8c7 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py @@ -170,7 +170,8 @@ class GitService: ) if ssh_key_path is not None: git_env_options["GIT_SSH_COMMAND"] = ( - "ssh -F /dev/null -o StrictHostKeyChecking=no -i %s" % ssh_key_path + "ssh -F /dev/null -o UserKnownHostsFile=/dev/null -o" + " StrictHostKeyChecking=no -i %s" % ssh_key_path ) # this is fine since we pass the commands directly From 012f5c20aad9aed49b6c29ccf72e37570ec73816 Mon Sep 17 00:00:00 2001 From: jasquat Date: Tue, 21 Feb 2023 17:08:09 -0500 Subject: [PATCH 16/41] fix git bash script unbound error w/ burnettk --- spiffworkflow-backend/bin/boot_server_in_docker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spiffworkflow-backend/bin/boot_server_in_docker b/spiffworkflow-backend/bin/boot_server_in_docker index 4ab98e324..fb425af5c 100755 --- a/spiffworkflow-backend/bin/boot_server_in_docker +++ b/spiffworkflow-backend/bin/boot_server_in_docker @@ -56,7 +56,7 @@ if [[ "${SPIFFWORKFLOW_BACKEND_RUN_DATA_SETUP:-}" != "false" ]]; then fi if [[ -n "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY:-}" ]]; then - if [[ -z "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH}" ]]; then + if [[ -z "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH:-}" ]]; then export SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH=$(mktemp /tmp/ssh_private_key.XXXXXX) fi chmod 600 "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH}" From 54248ca56898dbb6b1492f72e3348da8581fe104 Mon Sep 17 00:00:00 2001 From: burnettk Date: Tue, 21 Feb 2023 22:00:02 -0500 Subject: [PATCH 17/41] copy env so we are doing additive stuff rather than completely rewriting it --- .../services/git_service.py | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py index f7baba8c7..6ae385ad3 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py @@ -154,30 +154,31 @@ class GitService: cls, command: list[str], return_success_state: bool = False ) -> Union[subprocess.CompletedProcess[bytes], bool]: """Run_shell_command.""" - git_env_options = { - "GIT_COMMITTER_NAME": ( - current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USERNAME") - or "unknown" - ), - "GIT_COMMITTER_EMAIL": ( - current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL") - or "unknown@example.org" - ), - } + my_env = os.environ.copy() + my_env["GIT_COMMITTER_NAME"] = ( + current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USERNAME") or "unknown" + ) + + my_env["GIT_COMMITTER_EMAIL"] = ( + current_app.config.get("SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL") + or "unknown@example.org" + ) + # SSH authentication can be also provided via gitconfig. ssh_key_path = current_app.config.get( "SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH" ) if ssh_key_path is not None: - git_env_options["GIT_SSH_COMMAND"] = ( + my_env["GIT_SSH_COMMAND"] = ( "ssh -F /dev/null -o UserKnownHostsFile=/dev/null -o" " StrictHostKeyChecking=no -i %s" % ssh_key_path ) # this is fine since we pass the commands directly result = subprocess.run( # noqa - command, check=False, capture_output=True, env=git_env_options + command, check=False, capture_output=True, env=my_env ) + if return_success_state: return result.returncode == 0 From 4e94bca76a6581eafb4a0b37233bc187badd05c3 Mon Sep 17 00:00:00 2001 From: burnettk Date: Tue, 21 Feb 2023 22:30:17 -0500 Subject: [PATCH 18/41] make it so the message at the top of form is never strictly wrong --- .../src/themes/carbon/ErrorList/ErrorList.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spiffworkflow-frontend/src/themes/carbon/ErrorList/ErrorList.tsx b/spiffworkflow-frontend/src/themes/carbon/ErrorList/ErrorList.tsx index 58c28c11f..426a426bf 100644 --- a/spiffworkflow-frontend/src/themes/carbon/ErrorList/ErrorList.tsx +++ b/spiffworkflow-frontend/src/themes/carbon/ErrorList/ErrorList.tsx @@ -5,8 +5,8 @@ import { Tag } from '@carbon/react'; function ErrorList({ errors }: ErrorListProps) { if (errors) { return ( - - Please fill out required fields + + Some fields are invalid. Please correct them before submitting the form. ); } From bb6dd35bbd7439fe881e4cd966ab3fc2d5447da1 Mon Sep 17 00:00:00 2001 From: burnettk Date: Tue, 21 Feb 2023 22:43:23 -0500 Subject: [PATCH 19/41] remove start and end events from simple logs view --- .../routes/process_instances_controller.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py index 634d21285..7d0b48379 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py @@ -199,16 +199,18 @@ def process_instance_log_list( ) if not detailed: log_query = log_query.filter( - # 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 - # ) + # 1. 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 + # ) + # 2. We included ["End Event", "Default Start Event"] along with Default Throwing Event, but feb 2023 + # we decided to remove them, since they get really chatty when there are lots of subprocesses and call activities. and_( SpiffLoggingModel.message.in_(["State change to COMPLETED"]), # type: ignore SpiffLoggingModel.bpmn_task_type.in_( # type: ignore - ["Default Throwing Event", "End Event", "Default Start Event"] + ["Default Throwing Event"] ), ) ) From 5819b22cab80f433392501f7387c530a25f2791b Mon Sep 17 00:00:00 2001 From: jasquat Date: Wed, 22 Feb 2023 08:50:55 -0500 Subject: [PATCH 20/41] added support to validate custom errors in nested properties in json schema forms --- spiffworkflow-frontend/src/routes/TaskShow.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spiffworkflow-frontend/src/routes/TaskShow.tsx b/spiffworkflow-frontend/src/routes/TaskShow.tsx index 974f91d96..35ad48d43 100644 --- a/spiffworkflow-frontend/src/routes/TaskShow.tsx +++ b/spiffworkflow-frontend/src/routes/TaskShow.tsx @@ -168,6 +168,13 @@ export default function TaskShow() { } } } + + // recurse through all nested properties as well + getFieldsWithDateValidations( + propertyMetadata, + formData[propertyKey], + errors[propertyKey] + ); }); } return errors; From 769cc4126c7d9bb63505a9f29828747d53168899 Mon Sep 17 00:00:00 2001 From: jasquat Date: Wed, 22 Feb 2023 09:26:15 -0500 Subject: [PATCH 21/41] default to the for-me path on process instance show page links --- .../src/routes/ProcessInstanceShow.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index b7ffedb1e..e45fe6a26 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -115,6 +115,11 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { ); }; + let processInstanceShowPageBaseUrl = `/admin/process-instances/for-me/${params.process_model_id}/${params.process_instance_id}`; + if (variant === 'all') { + processInstanceShowPageBaseUrl = `/admin/process-instances/${params.process_model_id}/${params.process_instance_id}`; + } + useEffect(() => { if (permissionsLoaded) { const processTaskFailure = () => { @@ -254,11 +259,12 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { if (queryParamArray.length > 0) { queryParams = `?${queryParamArray.join('&')}`; } + return ( {label} @@ -282,7 +288,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { }; const returnToLastSpiffStep = () => { - window.location.href = `/admin/process-instances/${params.process_model_id}/${params.process_instance_id}`; + window.location.href = processInstanceShowPageBaseUrl; }; const resetProcessInstance = () => { From 2fa462387641f32293c5bdb58b94fe899cc8e977 Mon Sep 17 00:00:00 2001 From: Jon Herron Date: Wed, 22 Feb 2023 10:39:35 -0500 Subject: [PATCH 22/41] Add cumulative task data size to script --- .../scripts/get_data_sizes.py | 37 +++++++++++++++++++ .../services/process_instance_processor.py | 22 +++++++---- 2 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py new file mode 100644 index 000000000..1721bcdd6 --- /dev/null +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py @@ -0,0 +1,37 @@ +"""Get_data_sizes.""" +from typing import Any + +from spiffworkflow_backend.models.script_attributes_context import ( + ScriptAttributesContext, +) +from spiffworkflow_backend.scripts.script import Script +#from spiffworkflow_backend.servces.process_instance_processor import ProcessInstanceProcessor +from spiffworkflow_backend.services.process_instance_processor import ( + ProcessInstanceProcessor, +) + + +class GetDataSizes(Script): + """GetDataSizes.""" + + @staticmethod + def requires_privileged_permissions() -> bool: + """We have deemed this function safe to run without elevated permissions.""" + return False + + def get_description(self) -> str: + """Get_description.""" + return """Returns a dictionary of information about the size of task data and the python environment for the currently running process.""" + + def run( + self, + script_attributes_context: ScriptAttributesContext, + *_args: Any, + **kwargs: Any + ) -> Any: + """Run.""" + task = script_attributes_context.task + return { + "cumulative_task_data_size": ProcessInstanceProcessor.get_task_data_size(task.workflow), + "python_env_size": 0, + } diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 5aabe5acc..62bf61ad7 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -1602,16 +1602,24 @@ class ProcessInstanceProcessor: except WorkflowTaskException as we: raise ApiError.from_workflow_exception("task_error", str(we), we) from we - def check_task_data_size(self) -> None: - """CheckTaskDataSize.""" - tasks_to_check = self.bpmn_process_instance.get_tasks(TaskState.FINISHED_MASK) - task_data = [task.data for task in tasks_to_check] - task_data_to_check = list(filter(len, task_data)) + @classmethod + def _get_data_size(cls, data: Dict[Any, Any]) -> int: + data_to_check = list(filter(len, data)) try: - task_data_len = len(json.dumps(task_data_to_check)) + return len(json.dumps(data_to_check)) except Exception: - task_data_len = 0 + return 0 + + @classmethod + def get_task_data_size(cls, bpmn_process_instance: BpmnWorkflow) -> int: + tasks_to_check = bpmn_process_instance.get_tasks(TaskState.FINISHED_MASK) + task_data = [task.data for task in tasks_to_check] + return cls._get_data_size(task_data) + + def check_task_data_size(self) -> None: + """CheckTaskDataSize.""" + task_data_len = self.get_task_data_size(self.bpmn_process_instance) # Not sure what the number here should be but this now matches the mysql # max_allowed_packet variable on dev - 1073741824 From d5fa8eae21f8c6ff291c34fbe99e21c497f101cb Mon Sep 17 00:00:00 2001 From: Jon Herron Date: Wed, 22 Feb 2023 10:55:09 -0500 Subject: [PATCH 23/41] Adding python env size --- .../scripts/get_data_sizes.py | 2 +- .../services/process_instance_processor.py | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py index 1721bcdd6..038c6f8a6 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py @@ -33,5 +33,5 @@ class GetDataSizes(Script): task = script_attributes_context.task return { "cumulative_task_data_size": ProcessInstanceProcessor.get_task_data_size(task.workflow), - "python_env_size": 0, + "python_env_size": ProcessInstanceProcessor.get_python_env_size(task.workflow), } diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 62bf61ad7..1dfea5a5f 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -152,6 +152,11 @@ class BoxedTaskDataBasedScriptEngineEnvironment(BoxedTaskDataEnvironment): # ty super().execute(script, context, external_methods) self._last_result = context + def user_defined_state( + self, external_methods: Optional[Dict[str, Any]] = None + ) -> Dict[str, Any]: + return {} + def last_result(self) -> Dict[str, Any]: return {k: v for k, v in self._last_result.items()} @@ -218,13 +223,13 @@ class NonTaskDataBasedScriptEngineEnvironment(BasePythonScriptEngineEnvironment) for key_to_drop in context_keys_to_drop: context.pop(key_to_drop) - self.state = self._user_defined_state(external_methods) + self.state = self.user_defined_state(external_methods) # the task data needs to be updated with the current state so data references can be resolved properly. # the state will be removed later once the task is completed. context.update(self.state) - def _user_defined_state( + def user_defined_state( self, external_methods: Optional[Dict[str, Any]] = None ) -> Dict[str, Any]: keys_to_filter = self.non_user_defined_keys @@ -245,7 +250,7 @@ class NonTaskDataBasedScriptEngineEnvironment(BasePythonScriptEngineEnvironment) def preserve_state(self, bpmn_process_instance: BpmnWorkflow) -> None: key = self.PYTHON_ENVIRONMENT_STATE_KEY - state = self._user_defined_state() + state = self.user_defined_state() bpmn_process_instance.data[key] = state def restore_state(self, bpmn_process_instance: BpmnWorkflow) -> None: @@ -253,7 +258,7 @@ class NonTaskDataBasedScriptEngineEnvironment(BasePythonScriptEngineEnvironment) self.state = bpmn_process_instance.data.get(key, {}) def finalize_result(self, bpmn_process_instance: BpmnWorkflow) -> None: - bpmn_process_instance.data.update(self._user_defined_state()) + bpmn_process_instance.data.update(self.user_defined_state()) def revise_state_with_task_data(self, task: SpiffTask) -> None: state_keys = set(self.state.keys()) @@ -1617,6 +1622,11 @@ class ProcessInstanceProcessor: task_data = [task.data for task in tasks_to_check] return cls._get_data_size(task_data) + @classmethod + def get_python_env_size(cls, bpmn_process_instance: BpmnWorkflow) -> int: + user_defined_state = bpmn_process_instance.script_engine.environment.user_defined_state() + return cls._get_data_size(user_defined_state) + def check_task_data_size(self) -> None: """CheckTaskDataSize.""" task_data_len = self.get_task_data_size(self.bpmn_process_instance) From a4c0dd52ae8f1f4c6e0c09f5bda804a226439138 Mon Sep 17 00:00:00 2001 From: Jon Herron Date: Wed, 22 Feb 2023 11:04:07 -0500 Subject: [PATCH 24/41] Getting ./bin/pyl to pass --- .../spiffworkflow_backend/scripts/get_data_sizes.py | 11 ++++++++--- .../services/process_instance_processor.py | 4 +++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py index 038c6f8a6..2f28ffa71 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py @@ -5,11 +5,12 @@ from spiffworkflow_backend.models.script_attributes_context import ( ScriptAttributesContext, ) from spiffworkflow_backend.scripts.script import Script -#from spiffworkflow_backend.servces.process_instance_processor import ProcessInstanceProcessor from spiffworkflow_backend.services.process_instance_processor import ( ProcessInstanceProcessor, ) +# from spiffworkflow_backend.servces.process_instance_processor import ProcessInstanceProcessor + class GetDataSizes(Script): """GetDataSizes.""" @@ -32,6 +33,10 @@ class GetDataSizes(Script): """Run.""" task = script_attributes_context.task return { - "cumulative_task_data_size": ProcessInstanceProcessor.get_task_data_size(task.workflow), - "python_env_size": ProcessInstanceProcessor.get_python_env_size(task.workflow), + "cumulative_task_data_size": ProcessInstanceProcessor.get_task_data_size( + task.workflow + ), + "python_env_size": ProcessInstanceProcessor.get_python_env_size( + task.workflow + ), } diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 1dfea5a5f..0d0a641e2 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -1624,7 +1624,9 @@ class ProcessInstanceProcessor: @classmethod def get_python_env_size(cls, bpmn_process_instance: BpmnWorkflow) -> int: - user_defined_state = bpmn_process_instance.script_engine.environment.user_defined_state() + user_defined_state = ( + bpmn_process_instance.script_engine.environment.user_defined_state() + ) return cls._get_data_size(user_defined_state) def check_task_data_size(self) -> None: From 2afc19175ed80eb1e1ba9163538194a165b56e4d Mon Sep 17 00:00:00 2001 From: Jon Herron Date: Wed, 22 Feb 2023 11:17:23 -0500 Subject: [PATCH 25/41] Unfactor to fix size calculation/type hint issues --- .../scripts/get_data_sizes.py | 15 +++++++------ .../services/process_instance_processor.py | 22 +++++++++---------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py index 2f28ffa71..94dd2fd6a 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py @@ -22,7 +22,8 @@ class GetDataSizes(Script): def get_description(self) -> str: """Get_description.""" - return """Returns a dictionary of information about the size of task data and the python environment for the currently running process.""" + return """Returns a dictionary of information about the size of task data and + the python environment for the currently running process.""" def run( self, @@ -32,11 +33,11 @@ class GetDataSizes(Script): ) -> Any: """Run.""" task = script_attributes_context.task + cumulative_task_data_size = ProcessInstanceProcessor.get_task_data_size( + task.workflow + ) + python_env_size = ProcessInstanceProcessor.get_python_env_size(task.workflow) return { - "cumulative_task_data_size": ProcessInstanceProcessor.get_task_data_size( - task.workflow - ), - "python_env_size": ProcessInstanceProcessor.get_python_env_size( - task.workflow - ), + "cumulative_task_data_size": cumulative_task_data_size, + "python_env_size": python_env_size, } diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 0d0a641e2..5b728cd60 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -1607,27 +1607,27 @@ class ProcessInstanceProcessor: except WorkflowTaskException as we: raise ApiError.from_workflow_exception("task_error", str(we), we) from we - @classmethod - def _get_data_size(cls, data: Dict[Any, Any]) -> int: - data_to_check = list(filter(len, data)) - - try: - return len(json.dumps(data_to_check)) - except Exception: - return 0 - @classmethod def get_task_data_size(cls, bpmn_process_instance: BpmnWorkflow) -> int: tasks_to_check = bpmn_process_instance.get_tasks(TaskState.FINISHED_MASK) task_data = [task.data for task in tasks_to_check] - return cls._get_data_size(task_data) + task_data_to_check = list(filter(len, task_data)) + + try: + return len(json.dumps(task_data_to_check)) + except Exception: + return 0 @classmethod def get_python_env_size(cls, bpmn_process_instance: BpmnWorkflow) -> int: user_defined_state = ( bpmn_process_instance.script_engine.environment.user_defined_state() ) - return cls._get_data_size(user_defined_state) + + try: + return len(json.dumps(user_defined_state)) + except Exception: + return 0 def check_task_data_size(self) -> None: """CheckTaskDataSize.""" From 488abc03eabe7b13a865bf59c7c2316f1c03e7c7 Mon Sep 17 00:00:00 2001 From: Jon Herron Date: Wed, 22 Feb 2023 13:13:28 -0500 Subject: [PATCH 26/41] Provide info about keys in task data and python env --- .../scripts/get_data_sizes.py | 21 ++++++++++++------- .../services/process_instance_processor.py | 15 +++++++++---- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py index 94dd2fd6a..553d85c57 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py @@ -32,12 +32,17 @@ class GetDataSizes(Script): **kwargs: Any ) -> Any: """Run.""" - task = script_attributes_context.task - cumulative_task_data_size = ProcessInstanceProcessor.get_task_data_size( - task.workflow - ) - python_env_size = ProcessInstanceProcessor.get_python_env_size(task.workflow) - return { - "cumulative_task_data_size": cumulative_task_data_size, - "python_env_size": python_env_size, + workflow = script_attributes_context.task.workflow + task_data_size = ProcessInstanceProcessor.get_task_data_size(workflow) + task_data_keys_by_task = { + t.task_spec.name: sorted(t.data.keys()) + for t in ProcessInstanceProcessor.get_tasks_with_data(workflow) + } + python_env_size = ProcessInstanceProcessor.get_python_env_size(workflow) + python_env_keys = workflow.script_engine.environment.user_defined_state().keys() + return { + "python_env_size": python_env_size, + "python_env_keys": sorted(python_env_keys), + "task_data_size": task_data_size, + "task_data_keys_by_task": task_data_keys_by_task, } diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 5b728cd60..498ebadfa 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -1607,14 +1607,21 @@ class ProcessInstanceProcessor: except WorkflowTaskException as we: raise ApiError.from_workflow_exception("task_error", str(we), we) from we + @classmethod + def get_tasks_with_data(cls, bpmn_process_instance: BpmnWorkflow) -> List[SpiffTask]: + return [ + task + for task in bpmn_process_instance.get_tasks(TaskState.FINISHED_MASK) + if len(task.data) > 0 + ] + @classmethod def get_task_data_size(cls, bpmn_process_instance: BpmnWorkflow) -> int: - tasks_to_check = bpmn_process_instance.get_tasks(TaskState.FINISHED_MASK) - task_data = [task.data for task in tasks_to_check] - task_data_to_check = list(filter(len, task_data)) + tasks_with_data = cls.get_tasks_with_data(bpmn_process_instance) + all_task_data = [task.data for task in tasks_with_data] try: - return len(json.dumps(task_data_to_check)) + return len(json.dumps(all_task_data)) except Exception: return 0 From 7f2d69163e77b60d6c7189de2e477d769169adb7 Mon Sep 17 00:00:00 2001 From: Jon Herron Date: Wed, 22 Feb 2023 13:34:26 -0500 Subject: [PATCH 27/41] Getting ./bin/pyl to pass --- .../services/process_instance_processor.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 498ebadfa..86ff4490c 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -1608,7 +1608,9 @@ class ProcessInstanceProcessor: raise ApiError.from_workflow_exception("task_error", str(we), we) from we @classmethod - def get_tasks_with_data(cls, bpmn_process_instance: BpmnWorkflow) -> List[SpiffTask]: + def get_tasks_with_data( + cls, bpmn_process_instance: BpmnWorkflow + ) -> List[SpiffTask]: return [ task for task in bpmn_process_instance.get_tasks(TaskState.FINISHED_MASK) From 7fe8955adfc4b3f92847042aa4570001d7b7a0ed Mon Sep 17 00:00:00 2001 From: Jon Herron Date: Wed, 22 Feb 2023 13:42:45 -0500 Subject: [PATCH 28/41] Cleanup --- .../src/spiffworkflow_backend/scripts/get_data_sizes.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py index 553d85c57..ea4746748 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_data_sizes.py @@ -9,8 +9,6 @@ from spiffworkflow_backend.services.process_instance_processor import ( ProcessInstanceProcessor, ) -# from spiffworkflow_backend.servces.process_instance_processor import ProcessInstanceProcessor - class GetDataSizes(Script): """GetDataSizes.""" From 9fb490c7f92e62fd3f79b9a5f297000c6ab4fd61 Mon Sep 17 00:00:00 2001 From: burnettk Date: Wed, 22 Feb 2023 14:36:26 -0500 Subject: [PATCH 29/41] why not dict, too --- .../src/spiffworkflow_backend/config/default.py | 4 ++++ .../services/process_instance_processor.py | 1 + 2 files changed, 5 insertions(+) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py b/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py index d16dcd916..a08ef3e01 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py @@ -2,6 +2,10 @@ import re from os import environ +# Consider: https://flask.palletsprojects.com/en/2.2.x/config/#configuring-from-environment-variables +# and from_prefixed_env(), though we want to ensure that these variables are all documented, so that +# is a benefit of the status quo and having them all in this file explicitly. + SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR = environ.get( "SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR" ) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 5aabe5acc..a579f554f 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -293,6 +293,7 @@ class CustomBpmnScriptEngine(PythonScriptEngine): # type: ignore "enumerate": enumerate, "format": format, "list": list, + "dict": dict, "map": map, "pytz": pytz, "sum": sum, From c6b45dbdc3a15b740f281cb1c368cbfac82c6568 Mon Sep 17 00:00:00 2001 From: jasquat Date: Wed, 22 Feb 2023 14:42:43 -0500 Subject: [PATCH 30/41] show help text for textareas as well w/ burnettk --- .../services/process_instance_processor.py | 1 + .../src/themes/carbon/TextareaWidget/TextareaWidget.tsx | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 5aabe5acc..fbf3f05dd 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -1280,6 +1280,7 @@ class ProcessInstanceProcessor: # 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) + # waiting_tasks = bpmn_process_instance.get_waiting() # if len(waiting_tasks) > 0: # return ProcessInstanceStatus.waiting if len(user_tasks) > 0: diff --git a/spiffworkflow-frontend/src/themes/carbon/TextareaWidget/TextareaWidget.tsx b/spiffworkflow-frontend/src/themes/carbon/TextareaWidget/TextareaWidget.tsx index 082cc99d3..adec640c9 100644 --- a/spiffworkflow-frontend/src/themes/carbon/TextareaWidget/TextareaWidget.tsx +++ b/spiffworkflow-frontend/src/themes/carbon/TextareaWidget/TextareaWidget.tsx @@ -61,6 +61,11 @@ function TextareaWidget< labelToUse = `${labelToUse}*`; } + let helperText = null; + if (uiSchema && uiSchema['ui:help']) { + helperText = uiSchema['ui:help']; + } + let invalid = false; let errorMessageForField = null; if (rawErrors && rawErrors.length > 0) { @@ -73,6 +78,7 @@ function TextareaWidget< id={id} name={id} className="text-input" + helperText={helperText} value={value || ''} labelText="" placeholder={placeholder} From 1a29e123c1e21e4b87cdff09b746a4b7be93bbdc Mon Sep 17 00:00:00 2001 From: burnettk Date: Wed, 22 Feb 2023 15:16:13 -0500 Subject: [PATCH 31/41] so we do not lose our minds when debugging on a server --- spiffworkflow-backend/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spiffworkflow-backend/Dockerfile b/spiffworkflow-backend/Dockerfile index d7a4b0345..ef915bde3 100644 --- a/spiffworkflow-backend/Dockerfile +++ b/spiffworkflow-backend/Dockerfile @@ -8,11 +8,12 @@ ENV PATH="$VIRTUAL_ENV/bin:$PATH" WORKDIR /app # base plus packages needed for deployment. Could just install these in final, but then we can't cache as much. +# vim is just for debugging FROM base AS deployment RUN apt-get update \ && apt-get clean -y \ - && apt-get install -y -q curl git-core gunicorn3 default-mysql-client \ + && apt-get install -y -q curl git-core gunicorn3 default-mysql-client vim \ && rm -rf /var/lib/apt/lists/* # Setup image for installing Python dependencies. From a3126da7ef5adef168bf1607d4af82534e8046ce Mon Sep 17 00:00:00 2001 From: jasquat Date: Wed, 22 Feb 2023 15:34:47 -0500 Subject: [PATCH 32/41] set git user configs explicitly using the env vars w/ burnettk --- spiffworkflow-backend/bin/git_commit_bpmn_models_repo | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spiffworkflow-backend/bin/git_commit_bpmn_models_repo b/spiffworkflow-backend/bin/git_commit_bpmn_models_repo index 215e0ac9d..f34400ec5 100755 --- a/spiffworkflow-backend/bin/git_commit_bpmn_models_repo +++ b/spiffworkflow-backend/bin/git_commit_bpmn_models_repo @@ -33,6 +33,13 @@ function run() { return fi + # FIXME: the environment variables may not be working with the root user which we are using in the docker container. + # we see some evidence with this issue https://stackoverflow.com/questions/68975943/git-config-environment-variables + # and it didn't seem to work for us either so set them like this for now. + # One day we should probably not use the root user in the docker container. + git config --local user.email "$GIT_COMMITTER_EMAIL" + git config --local user.name "$GIT_COMMITTER_NAME" + git commit -m "${git_commit_message}" git push --set-upstream origin "${git_branch}" } From 1daaf7995c7f84657b6d9cf30ac5a4e433331913 Mon Sep 17 00:00:00 2001 From: burnettk Date: Thu, 23 Feb 2023 09:53:52 -0500 Subject: [PATCH 33/41] update spiffworkflow --- poetry.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/poetry.lock b/poetry.lock index 98a702061..0b2f93df2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -45,11 +45,11 @@ dev = ["black", "coverage", "isort", "pre-commit", "pyenchant", "pylint"] [[package]] name = "apscheduler" -version = "3.9.1" +version = "3.10.0" description = "In-process task scheduler with Cron-like capabilities" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +python-versions = ">=3.6" [package.dependencies] pytz = "*" @@ -58,14 +58,13 @@ six = ">=1.4.0" tzlocal = ">=2.0,<3.0.0 || >=4.0.0" [package.extras] -asyncio = ["trollius"] doc = ["sphinx", "sphinx-rtd-theme"] gevent = ["gevent"] mongodb = ["pymongo (>=3.0)"] redis = ["redis (>=3.0)"] rethinkdb = ["rethinkdb (>=2.4.0)"] -sqlalchemy = ["sqlalchemy (>=0.8)"] -testing = ["mock", "pytest", "pytest-asyncio", "pytest-asyncio (<0.6)", "pytest-cov", "pytest-tornado5"] +sqlalchemy = ["sqlalchemy (>=1.4)"] +testing = ["pytest", "pytest-asyncio", "pytest-cov", "pytest-tornado5"] tornado = ["tornado (>=4.3)"] twisted = ["twisted"] zookeeper = ["kazoo"] @@ -1760,7 +1759,7 @@ lxml = "*" type = "git" url = "https://github.com/sartography/SpiffWorkflow" reference = "main" -resolved_reference = "0e61be85c47474a33037e6f398e64c96e02f13ad" +resolved_reference = "2ca6ebf800d4ff1d54f3e1c48798a2cb879560f7" [[package]] name = "sqlalchemy" @@ -2131,8 +2130,8 @@ aniso8601 = [ {file = "aniso8601-9.0.1.tar.gz", hash = "sha256:72e3117667eedf66951bb2d93f4296a56b94b078a8a95905a052611fb3f1b973"}, ] apscheduler = [ - {file = "APScheduler-3.9.1-py2.py3-none-any.whl", hash = "sha256:ddc25a0ddd899de44d7f451f4375fb971887e65af51e41e5dcf681f59b8b2c9a"}, - {file = "APScheduler-3.9.1.tar.gz", hash = "sha256:65e6574b6395498d371d045f2a8a7e4f7d50c6ad21ef7313d15b1c7cf20df1e3"}, + {file = "APScheduler-3.10.0-py3-none-any.whl", hash = "sha256:575299f20073c60a2cc9d4fa5906024cdde33c5c0ce6087c4e3c14be3b50fdd4"}, + {file = "APScheduler-3.10.0.tar.gz", hash = "sha256:a49fc23269218416f0e41890eea7a75ed6b284f10630dcfe866ab659621a3696"}, ] astroid = [ {file = "astroid-2.12.12-py3-none-any.whl", hash = "sha256:72702205200b2a638358369d90c222d74ebc376787af8fb2f7f2a86f7b5cc85f"}, @@ -2521,6 +2520,7 @@ lazy-object-proxy = [ {file = "lazy_object_proxy-1.8.0-pp39-pypy39_pp73-any.whl", hash = "sha256:ce58b2b3734c73e68f0e30e4e725264d4d6be95818ec0a0be4bb6bf9a7e79aa8"}, ] livereload = [ + {file = "livereload-2.6.3-py2.py3-none-any.whl", hash = "sha256:ad4ac6f53b2d62bb6ce1a5e6e96f1f00976a32348afedcb4b6d68df2a1d346e4"}, {file = "livereload-2.6.3.tar.gz", hash = "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"}, ] lxml = [ From 81a402dd7d12f67b5b464d43c56cec5987904ffb Mon Sep 17 00:00:00 2001 From: jasquat Date: Thu, 23 Feb 2023 10:23:26 -0500 Subject: [PATCH 34/41] logs list page should respect the for-me variant --- .../src/routes/AdminRoutes.tsx | 6 +++++- .../src/routes/ProcessInstanceLogList.tsx | 18 ++++++++++++------ .../src/routes/ProcessInstanceShow.tsx | 4 +++- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/spiffworkflow-frontend/src/routes/AdminRoutes.tsx b/spiffworkflow-frontend/src/routes/AdminRoutes.tsx index 43eba9218..d183dc013 100644 --- a/spiffworkflow-frontend/src/routes/AdminRoutes.tsx +++ b/spiffworkflow-frontend/src/routes/AdminRoutes.tsx @@ -110,7 +110,11 @@ export default function AdminRoutes() { /> } + element={} + /> + } /> { const setProcessInstanceLogListFromResult = (result: any) => { setProcessInstanceLogs(result.results); @@ -65,7 +71,7 @@ export default function ProcessInstanceLogList() { {convertSecondsToFormattedDateTime(rowToUse.timestamp)} @@ -111,7 +117,7 @@ export default function ProcessInstanceLogList() { }, [ `Process Instance: ${params.process_instance_id}`, - `/admin/process-instances/${params.process_model_id}/${params.process_instance_id}`, + `${processInstanceShowPageBaseUrl}/${params.process_instance_id}`, ], ['Logs'], ]} diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index e45fe6a26..297c92517 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -116,8 +116,10 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { }; let processInstanceShowPageBaseUrl = `/admin/process-instances/for-me/${params.process_model_id}/${params.process_instance_id}`; + let processInstanceLogListPageBaseUrl = `/admin/logs/for-me/${params.process_model_id}/${params.process_instance_id}`; if (variant === 'all') { processInstanceShowPageBaseUrl = `/admin/process-instances/${params.process_model_id}/${params.process_instance_id}`; + processInstanceLogListPageBaseUrl = `/admin/logs/${params.process_model_id}/${params.process_instance_id}`; } useEffect(() => { @@ -459,7 +461,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { size="sm" className="button-white-background" data-qa="process-instance-log-list-link" - href={`/admin/logs/${modifiedProcessModelId}/${params.process_instance_id}`} + href={`${processInstanceLogListPageBaseUrl}`} > Logs From 7a60c13f90afe056e76514af76b31bf3184454de Mon Sep 17 00:00:00 2001 From: burnettk Date: Thu, 23 Feb 2023 10:42:56 -0500 Subject: [PATCH 35/41] Squashed 'SpiffWorkflow/' changes from 11e4b4f9..2ca6ebf8 2ca6ebf8 Data stores (#298) c2fc9d22 Merge pull request #297 from sartography/bugfix/copy-all-data-when-input-or-output-list-empty 07e3b582 add checks for len == 0 when copying based on io spec b439f69f Merge pull request #296 from sartography/bugfix/subprocess-access-to-data-objects 6d2a2031 update spiff subworkflow tasks too 992c3867 make data objects referenceable within subprocesses 6c8ff5cd allow subprocesses & call activities to have different data copy policies 2b14f3a4 initialize subprocesses in _update_hook instead of _on_ready_before 791f335d Merge pull request #295 from sartography/improvement/remove-camunda-from-base-and-misc-cleanup 28b579be remove a few unused, duplicative, and debugging methods 8f14d109 remove some other unused diagrams and tests 408bc673 rely on top level camunda parser for almost all namespace references 895b2cc9 remove camunda namespace from base bpmn parser 76ecbf7c Merge pull request #294 from sartography/bugfix/reactivate-boundary-event 82b6c8ad hack to ensure timers (and other events) are reset if returned to via loop reset 590903f4 Merge pull request #292 from sartography/feature/multiinstance-refactor 53749004 fix bug & typo f31726db raise error on attempting to migrate workflows with MI 44e6d08d create spiff multiinstance task 2168c022 create camunda MI that approximates what it used to do 9894cea5 some improvements and bugfixes f857ad5d remove some now unused functionality & tests, create a few more tests 6fead9d0 updated serializer & fixes for most tests ec662ecd add parallel multiinstance bd19b2a8 working sequential multiinstance 2f9c192b further cleanup around _update_hook 947792bf fix bug in exclusive gateway migration d3d87b28 add io spec to all tasks f1586e27 add support for standard loop tasks git-subtree-dir: SpiffWorkflow git-subtree-split: 2ca6ebf800d4ff1d54f3e1c48798a2cb879560f7 --- tests/SpiffWorkflow/TaskTest.py | 12 +- tests/SpiffWorkflow/bpmn/AntiLoopTaskTest.py | 42 - .../SpiffWorkflow/bpmn/BpmnLoaderForTests.py | 38 +- .../bpmn/BpmnWorkflowTestCase.py | 7 +- .../bpmn/DataObjectReferenceTest.py | 6 +- .../bpmn/DataStoreReferenceTest.py | 36 + .../ExclusiveGatewayIntoMultiInstanceTest.py | 38 - ...lsiveGatewayNonDefaultPathIntoMultiTest.py | 59 -- tests/SpiffWorkflow/bpmn/IOSpecTest.py | 49 +- tests/SpiffWorkflow/bpmn/LoopTaskTest.py | 60 -- .../bpmn/MultiInstanceParallelCondTest.py | 54 -- .../bpmn/MultiInstanceParallelTest.py | 51 -- tests/SpiffWorkflow/bpmn/MultiInstanceTest.py | 46 - .../bpmn/ParallelMultiInstanceTest.py | 233 +++++ tests/SpiffWorkflow/bpmn/ParallelOrderTest.py | 10 +- .../bpmn/ParallelWithScriptTest.py | 25 - tests/SpiffWorkflow/bpmn/ParserTest.py | 4 +- tests/SpiffWorkflow/bpmn/ResetTimerTest.py | 28 + .../bpmn/SequentialMultiInstanceTest.py | 213 +++++ tests/SpiffWorkflow/bpmn/StandardLoopTest.py | 62 ++ .../bpmn/SubWorkflowMultiTest.py | 51 -- .../bpmn/data/MultiInstanceParallelTask.bpmn | 59 -- .../data/MultiInstanceParallelTaskCond.bpmn | 145 --- .../bpmn/data/ParallelWithScript.bpmn | 117 --- .../bpmn/data/bpmnAntiLoopTask.bpmn | 47 - .../SpiffWorkflow/bpmn/data/bpmnLoopTask.bpmn | 45 - .../bpmn/data/bpmnMultiUserTask.bpmn | 49 -- .../SpiffWorkflow/bpmn/data/data_object.bpmn | 14 +- tests/SpiffWorkflow/bpmn/data/data_store.bpmn | 89 ++ .../bpmn/data/data_store_read.bpmn | 91 ++ .../bpmn/data/data_store_write.bpmn | 91 ++ .../bpmn/data/exclusive_into_multi.bpmn | 83 -- ...exclusive_non_default_path_into_multi.bpmn | 97 -- tests/SpiffWorkflow/bpmn/data/io_spec.bpmn | 6 +- .../bpmn/data/io_spec_on_task.bpmn | 66 ++ .../parallel_multiinstance_cardinality.bpmn | 44 + .../data/parallel_multiinstance_invalid.bpmn | 45 + .../parallel_multiinstance_loop_input.bpmn | 44 + .../SpiffWorkflow/bpmn/data/reset_timer.bpmn | 104 +++ .../sequential_multiinstance_cardinality.bpmn | 44 + .../sequential_multiinstance_loop_input.bpmn | 44 + .../bpmn/data/serialization/v1.1-data.json | 731 +++++++++++++++ .../data/serialization/v1.1-gateways.json | 830 ++++++++++++++++++ .../bpmn/data/serialization/v1.1-multi.json | 350 ++++++++ .../{v1-1.json => v1.1-timers.json} | 0 .../bpmn/data/standard_loop.bpmn | 41 + .../bpmn/data/standard_loop_invalid.bpmn | 39 + .../bpmn/data/sub_within_sub_multi.bpmn | 129 --- .../bpmn/data/sub_workflow_multi.bpmn | 93 -- .../bpmn/data/sub_workflow_multi1.bpmn | 59 -- .../data/sub_workflow_multi_parallel.bpmn | 93 -- .../bpmn/data/two_top_level_procs.bpmn | 79 -- .../bpmn/events/EventBasedGatewayTest.py | 2 +- .../bpmn/events/TransactionSubprocssTest.py | 26 +- .../bpmn/serializer/VersionMigrationTest.py | 37 +- .../camunda/DefaultGatewayPMITest.py | 60 -- .../camunda/ExclusiveGatewayPMITest.py | 68 -- .../camunda/MultiInstanceArrayTest.py | 222 ----- .../camunda/MultiInstanceDMNTest.py | 13 +- .../camunda/MultiInstanceDeepDictEdit.py | 113 --- .../camunda/MultiInstanceParallelArrayTest.py | 98 --- .../camunda/ParseMultiInstanceTest.py | 91 ++ .../camunda/ResetTokenMIParallelTest.py | 80 -- .../SpiffWorkflow/camunda/ResetTokenMITest.py | 81 -- .../camunda/data/DMNMultiInstance.bpmn | 62 +- .../camunda/data/common_workflow.bpmn | 89 -- .../camunda/data/default_gateway_pmi.bpmn | 89 -- .../camunda/data/multi_instance_array.bpmn | 99 --- .../data/multi_instance_array_parallel.bpmn | 99 --- ...ulti_instance_parallel_deep_data_edit.bpmn | 66 -- .../parallel_multiinstance_cardinality.bpmn | 41 + .../parallel_multiinstance_collection.bpmn | 39 + .../camunda/data/token_trial_MI.bpmn | 83 -- .../camunda/data/token_trial_MIParallel.bpmn | 83 -- tests/SpiffWorkflow/specs/ExecuteTest.py | 5 +- tests/SpiffWorkflow/specs/TaskSpecTest.py | 19 +- tests/SpiffWorkflow/specs/WorkflowSpecTest.py | 4 +- tests/SpiffWorkflow/spiff/BaseTestCase.py | 1 - tests/SpiffWorkflow/spiff/CorrelationTest.py | 7 - .../spiff/MultiInstanceTaskTest.py | 29 + .../spiff/data/spiff_multiinstance.bpmn | 49 ++ 81 files changed, 3649 insertions(+), 2998 deletions(-) delete mode 100644 tests/SpiffWorkflow/bpmn/AntiLoopTaskTest.py create mode 100644 tests/SpiffWorkflow/bpmn/DataStoreReferenceTest.py delete mode 100644 tests/SpiffWorkflow/bpmn/ExclusiveGatewayIntoMultiInstanceTest.py delete mode 100644 tests/SpiffWorkflow/bpmn/ExculsiveGatewayNonDefaultPathIntoMultiTest.py delete mode 100644 tests/SpiffWorkflow/bpmn/LoopTaskTest.py delete mode 100644 tests/SpiffWorkflow/bpmn/MultiInstanceParallelCondTest.py delete mode 100644 tests/SpiffWorkflow/bpmn/MultiInstanceParallelTest.py delete mode 100644 tests/SpiffWorkflow/bpmn/MultiInstanceTest.py create mode 100644 tests/SpiffWorkflow/bpmn/ParallelMultiInstanceTest.py delete mode 100644 tests/SpiffWorkflow/bpmn/ParallelWithScriptTest.py create mode 100644 tests/SpiffWorkflow/bpmn/ResetTimerTest.py create mode 100644 tests/SpiffWorkflow/bpmn/SequentialMultiInstanceTest.py create mode 100644 tests/SpiffWorkflow/bpmn/StandardLoopTest.py delete mode 100644 tests/SpiffWorkflow/bpmn/SubWorkflowMultiTest.py delete mode 100644 tests/SpiffWorkflow/bpmn/data/MultiInstanceParallelTask.bpmn delete mode 100644 tests/SpiffWorkflow/bpmn/data/MultiInstanceParallelTaskCond.bpmn delete mode 100644 tests/SpiffWorkflow/bpmn/data/ParallelWithScript.bpmn delete mode 100644 tests/SpiffWorkflow/bpmn/data/bpmnAntiLoopTask.bpmn delete mode 100644 tests/SpiffWorkflow/bpmn/data/bpmnLoopTask.bpmn delete mode 100644 tests/SpiffWorkflow/bpmn/data/bpmnMultiUserTask.bpmn create mode 100644 tests/SpiffWorkflow/bpmn/data/data_store.bpmn create mode 100644 tests/SpiffWorkflow/bpmn/data/data_store_read.bpmn create mode 100644 tests/SpiffWorkflow/bpmn/data/data_store_write.bpmn delete mode 100644 tests/SpiffWorkflow/bpmn/data/exclusive_into_multi.bpmn delete mode 100644 tests/SpiffWorkflow/bpmn/data/exclusive_non_default_path_into_multi.bpmn create mode 100644 tests/SpiffWorkflow/bpmn/data/io_spec_on_task.bpmn create mode 100644 tests/SpiffWorkflow/bpmn/data/parallel_multiinstance_cardinality.bpmn create mode 100644 tests/SpiffWorkflow/bpmn/data/parallel_multiinstance_invalid.bpmn create mode 100644 tests/SpiffWorkflow/bpmn/data/parallel_multiinstance_loop_input.bpmn create mode 100644 tests/SpiffWorkflow/bpmn/data/reset_timer.bpmn create mode 100644 tests/SpiffWorkflow/bpmn/data/sequential_multiinstance_cardinality.bpmn create mode 100644 tests/SpiffWorkflow/bpmn/data/sequential_multiinstance_loop_input.bpmn create mode 100644 tests/SpiffWorkflow/bpmn/data/serialization/v1.1-data.json create mode 100644 tests/SpiffWorkflow/bpmn/data/serialization/v1.1-gateways.json create mode 100644 tests/SpiffWorkflow/bpmn/data/serialization/v1.1-multi.json rename tests/SpiffWorkflow/bpmn/data/serialization/{v1-1.json => v1.1-timers.json} (100%) create mode 100644 tests/SpiffWorkflow/bpmn/data/standard_loop.bpmn create mode 100644 tests/SpiffWorkflow/bpmn/data/standard_loop_invalid.bpmn delete mode 100644 tests/SpiffWorkflow/bpmn/data/sub_within_sub_multi.bpmn delete mode 100644 tests/SpiffWorkflow/bpmn/data/sub_workflow_multi.bpmn delete mode 100644 tests/SpiffWorkflow/bpmn/data/sub_workflow_multi1.bpmn delete mode 100644 tests/SpiffWorkflow/bpmn/data/sub_workflow_multi_parallel.bpmn delete mode 100644 tests/SpiffWorkflow/bpmn/data/two_top_level_procs.bpmn delete mode 100644 tests/SpiffWorkflow/camunda/DefaultGatewayPMITest.py delete mode 100644 tests/SpiffWorkflow/camunda/ExclusiveGatewayPMITest.py delete mode 100644 tests/SpiffWorkflow/camunda/MultiInstanceArrayTest.py delete mode 100644 tests/SpiffWorkflow/camunda/MultiInstanceDeepDictEdit.py delete mode 100644 tests/SpiffWorkflow/camunda/MultiInstanceParallelArrayTest.py create mode 100644 tests/SpiffWorkflow/camunda/ParseMultiInstanceTest.py delete mode 100644 tests/SpiffWorkflow/camunda/ResetTokenMIParallelTest.py delete mode 100644 tests/SpiffWorkflow/camunda/ResetTokenMITest.py delete mode 100644 tests/SpiffWorkflow/camunda/data/common_workflow.bpmn delete mode 100644 tests/SpiffWorkflow/camunda/data/default_gateway_pmi.bpmn delete mode 100644 tests/SpiffWorkflow/camunda/data/multi_instance_array.bpmn delete mode 100644 tests/SpiffWorkflow/camunda/data/multi_instance_array_parallel.bpmn delete mode 100644 tests/SpiffWorkflow/camunda/data/multi_instance_parallel_deep_data_edit.bpmn create mode 100644 tests/SpiffWorkflow/camunda/data/parallel_multiinstance_cardinality.bpmn create mode 100644 tests/SpiffWorkflow/camunda/data/parallel_multiinstance_collection.bpmn delete mode 100644 tests/SpiffWorkflow/camunda/data/token_trial_MI.bpmn delete mode 100644 tests/SpiffWorkflow/camunda/data/token_trial_MIParallel.bpmn create mode 100644 tests/SpiffWorkflow/spiff/MultiInstanceTaskTest.py create mode 100644 tests/SpiffWorkflow/spiff/data/spiff_multiinstance.bpmn diff --git a/tests/SpiffWorkflow/TaskTest.py b/tests/SpiffWorkflow/TaskTest.py index e44f68e6f..77e28df61 100644 --- a/tests/SpiffWorkflow/TaskTest.py +++ b/tests/SpiffWorkflow/TaskTest.py @@ -1,12 +1,9 @@ # -*- coding: utf-8 -*- -import sys import unittest import re -import os.path -sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) -from SpiffWorkflow.task import Task, TaskState, updateDotDict +from SpiffWorkflow.task import Task, TaskState from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.specs.Simple import Simple @@ -15,10 +12,6 @@ class MockWorkflow(object): def __init__(self, spec): self.spec = spec -class UpdateDotDictTest(unittest.TestCase): - def test_update(self): - res = updateDotDict({}, 'some.thing.here', 'avalue') - self.assertEqual(res, {'some':{'thing': {'here': 'avalue'}}}) class TaskTest(unittest.TestCase): @@ -85,8 +78,7 @@ class TaskTest(unittest.TestCase): def suite(): taskSuite = unittest.TestLoader().loadTestsFromTestCase(TaskTest) - updateDotSuite = unittest.TestLoader().loadTestsFromTestCase(UpdateDotDictTest) - return unittest.TestSuite([taskSuite, updateDotSuite]) + return unittest.TestSuite([taskSuite]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/bpmn/AntiLoopTaskTest.py b/tests/SpiffWorkflow/bpmn/AntiLoopTaskTest.py deleted file mode 100644 index c398ca834..000000000 --- a/tests/SpiffWorkflow/bpmn/AntiLoopTaskTest.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- - - - -import unittest -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from SpiffWorkflow.exceptions import WorkflowException -from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase - -__author__ = 'kellym' - - -class AntiLoopTaskTest(BpmnWorkflowTestCase): - """The example bpmn is actually a MultiInstance. It should not report that it is a looping task and - it should fail when we try to terminate the loop""" - - def setUp(self): - spec, subprocesses = self.load_workflow_spec('bpmnAntiLoopTask.bpmn','LoopTaskTest') - self.workflow = BpmnWorkflow(spec, subprocesses) - - def testRunThroughHappy(self): - - self.workflow.do_engine_steps() - ready_tasks = self.workflow.get_ready_user_tasks() - self.assertTrue(len(ready_tasks) ==1) - self.assertFalse(ready_tasks[0].task_spec.is_loop_task()) - try: - ready_tasks[0].terminate_loop() - self.fail("Terminate Loop should throw and error when called on a non-loop MultiInstance") - except WorkflowException as ex: - self.assertTrue( - 'The method terminate_loop should only be called in the case of a BPMN Loop Task' in ( - '%r' % ex), - '\'The method terminate_loop should only be called in the case of a BPMN Loop Task\' should be a substring of error message: \'%r\'' % ex) - - - - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(AntiLoopTaskTest) -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/bpmn/BpmnLoaderForTests.py b/tests/SpiffWorkflow/bpmn/BpmnLoaderForTests.py index 2623e6887..d8420daa8 100644 --- a/tests/SpiffWorkflow/bpmn/BpmnLoaderForTests.py +++ b/tests/SpiffWorkflow/bpmn/BpmnLoaderForTests.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from SpiffWorkflow.bpmn.specs.data_spec import BpmnDataStoreSpecification from SpiffWorkflow.bpmn.specs.ExclusiveGateway import ExclusiveGateway from SpiffWorkflow.bpmn.specs.UserTask import UserTask from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnParser @@ -7,7 +8,7 @@ from SpiffWorkflow.bpmn.parser.TaskParser import TaskParser from SpiffWorkflow.bpmn.parser.task_parsers import ConditionalGatewayParser from SpiffWorkflow.bpmn.parser.util import full_tag -from SpiffWorkflow.bpmn.serializer.helpers.spec import TaskSpecConverter +from SpiffWorkflow.bpmn.serializer.helpers.spec import BpmnSpecConverter, TaskSpecConverter # Many of our tests relied on the Packager to set the calledElement attribute on # Call Activities. I've moved that code to a customized parser. @@ -57,6 +58,38 @@ class TestUserTaskConverter(TaskSpecConverter): def from_dict(self, dct): return self.task_spec_from_dict(dct) +class TestDataStore(BpmnDataStoreSpecification): + + _value = None + + def get(self, my_task): + """Copy a value from a data store into task data.""" + my_task.data[self.name] = TestDataStore._value + + def set(self, my_task): + """Copy a value from the task data to the data store""" + TestDataStore._value = my_task.data[self.name] + del my_task.data[self.name] + +class TestDataStoreConverter(BpmnSpecConverter): + + def __init__(self, registry): + super().__init__(TestDataStore, registry) + + def to_dict(self, spec): + return { + "name": spec.name, + "description": spec.description, + "capacity": spec.capacity, + "is_unlimited": spec.is_unlimited, + "_value": TestDataStore._value, + } + + def from_dict(self, dct): + _value = dct.pop("_value") + data_store = TestDataStore(**dct) + TestDataStore._value = _value + return data_store class TestBpmnParser(BpmnParser): OVERRIDE_PARSER_CLASSES = { @@ -65,3 +98,6 @@ class TestBpmnParser(BpmnParser): full_tag('callActivity'): (CallActivityParser, CallActivity) } + DATA_STORE_CLASSES = { + "TestDataStore": TestDataStore, + } diff --git a/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py b/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py index ba564abc8..d16a87920 100644 --- a/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py +++ b/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py @@ -8,13 +8,12 @@ from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnValidator from SpiffWorkflow.task import TaskState from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer, DEFAULT_SPEC_CONFIG -from SpiffWorkflow.bpmn.serializer.task_spec import UserTaskConverter -from .BpmnLoaderForTests import TestUserTaskConverter, TestBpmnParser +from .BpmnLoaderForTests import TestUserTaskConverter, TestBpmnParser, TestDataStoreConverter __author__ = 'matth' DEFAULT_SPEC_CONFIG['task_specs'].append(TestUserTaskConverter) - +DEFAULT_SPEC_CONFIG['task_specs'].append(TestDataStoreConverter) wf_spec_converter = BpmnWorkflowSerializer.configure_workflow_spec_converter(spec_config=DEFAULT_SPEC_CONFIG) @@ -121,6 +120,7 @@ class BpmnWorkflowTestCase(unittest.TestCase): def save_restore(self): + script_engine = self.workflow.script_engine before_state = self._get_workflow_state(do_steps=False) before_dump = self.workflow.get_dump() # Check that we can actully convert this to JSON @@ -133,6 +133,7 @@ class BpmnWorkflowTestCase(unittest.TestCase): self.assertEqual(before_dump, after_dump) self.assertEqual(before_state, after_state) self.workflow = after + self.workflow.script_engine = script_engine def restore(self, state): self.workflow = self.serializer.workflow_from_dict(state) diff --git a/tests/SpiffWorkflow/bpmn/DataObjectReferenceTest.py b/tests/SpiffWorkflow/bpmn/DataObjectReferenceTest.py index 0254c5df4..fab8db77b 100644 --- a/tests/SpiffWorkflow/bpmn/DataObjectReferenceTest.py +++ b/tests/SpiffWorkflow/bpmn/DataObjectReferenceTest.py @@ -72,11 +72,15 @@ class DataObjectReferenceTest(BpmnWorkflowTestCase): self.assertNotIn('obj_1', ready_tasks[0].data) self.assertEqual(self.workflow.data['obj_1'], 'hello') - # Make sure data objects can be copied in and out of a subprocess + # Make sure data objects are accessible inside a subprocess self.workflow.do_engine_steps() ready_tasks = self.workflow.get_ready_user_tasks() self.assertEqual(ready_tasks[0].data['obj_1'], 'hello') + ready_tasks[0].data['obj_1'] = 'hello again' ready_tasks[0].complete() self.workflow.do_engine_steps() sp = self.workflow.get_tasks_from_spec_name('subprocess')[0] + # It was copied out self.assertNotIn('obj_1', sp.data) + # The update should persist in the main process + self.assertEqual(self.workflow.data['obj_1'], 'hello again') diff --git a/tests/SpiffWorkflow/bpmn/DataStoreReferenceTest.py b/tests/SpiffWorkflow/bpmn/DataStoreReferenceTest.py new file mode 100644 index 000000000..a9e3d7358 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/DataStoreReferenceTest.py @@ -0,0 +1,36 @@ +from tests.SpiffWorkflow.bpmn.BpmnLoaderForTests import TestDataStore +from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase +from SpiffWorkflow.bpmn.exceptions import WorkflowDataException +from SpiffWorkflow.bpmn.workflow import BpmnWorkflow + +class DataStoreReferenceTest(BpmnWorkflowTestCase): + def _do_engine_steps(self, file, processid, save_restore): + spec, subprocesses = self.load_workflow_spec('data_store.bpmn', 'JustDataStoreRef') + self.workflow = BpmnWorkflow(spec, subprocesses) + if save_restore: + self.save_restore() + self.workflow.do_engine_steps() + + def _check_last_script_task_data(self): + last_script_task_data = self.workflow.get_tasks_from_spec_name("Activity_1skgyn9")[0].data + self.assertEqual(len(last_script_task_data), 1) + self.assertEqual(last_script_task_data["x"], "Sue") + + def testCanInterpretDataStoreReferenceWithInputsAndOutputs(self): + self._do_engine_steps('data_store.bpmn', 'JustDataStoreRef', False) + self._check_last_script_task_data() + + def testCanSaveRestoreDataStoreReferenceWithInputsAndOutputs(self): + self._do_engine_steps('data_store.bpmn', 'JustDataStoreRef', True) + self._check_last_script_task_data() + + def testSeparateWorkflowInstancesCanShareDataUsingDataStores(self): + self._do_engine_steps('data_store_write.bpmn', 'JustDataStoreRef', False) + self._do_engine_steps('data_store_read.bpmn', 'JustDataStoreRef', False) + self._check_last_script_task_data() + + def testSeparateRestoredWorkflowInstancesCanShareDataUsingDataStores(self): + self._do_engine_steps('data_store_write.bpmn', 'JustDataStoreRef', True) + self._do_engine_steps('data_store_read.bpmn', 'JustDataStoreRef', True) + self._check_last_script_task_data() + diff --git a/tests/SpiffWorkflow/bpmn/ExclusiveGatewayIntoMultiInstanceTest.py b/tests/SpiffWorkflow/bpmn/ExclusiveGatewayIntoMultiInstanceTest.py deleted file mode 100644 index 8eaaff418..000000000 --- a/tests/SpiffWorkflow/bpmn/ExclusiveGatewayIntoMultiInstanceTest.py +++ /dev/null @@ -1,38 +0,0 @@ -# -*- coding: utf-8 -*- - - - -import sys -import os -import unittest -sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase - -__author__ = 'matth' - - -class ExclusiveGatewayIntoMultiInstanceTest(BpmnWorkflowTestCase): - """In the example BPMN Diagram we set x = 0, then we have an - exclusive gateway that should skip over a parallel multi-instance - class, so it should run straight through and complete without issue.""" - - def setUp(self): - spec, subprocesses = self.load_workflow_spec('exclusive_into_multi.bpmn','ExclusiveToMulti') - self.workflow = BpmnWorkflow(spec, subprocesses) - - def testRunThroughHappy(self): - - - self.workflow.do_engine_steps() - self.assertTrue(self.workflow.is_completed()) - - def testSaveRestore(self): - - self.workflow.do_engine_steps() - self.assertTrue(self.workflow.is_completed()) - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(ExclusiveGatewayIntoMultiInstanceTest) -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/bpmn/ExculsiveGatewayNonDefaultPathIntoMultiTest.py b/tests/SpiffWorkflow/bpmn/ExculsiveGatewayNonDefaultPathIntoMultiTest.py deleted file mode 100644 index 424f72e9b..000000000 --- a/tests/SpiffWorkflow/bpmn/ExculsiveGatewayNonDefaultPathIntoMultiTest.py +++ /dev/null @@ -1,59 +0,0 @@ -# -*- coding: utf-8 -*- - - - -import sys -import os -import unittest -sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase - -__author__ = 'matth' - - -class ExclusiveGatewayNonDefaultPathIntoMultiTest(BpmnWorkflowTestCase): - """In the example BPMN Diagram we require that "Yes" or "No" be specified - in a user task and check that a multiinstance can follow a non-default - path. - """ - - def setUp(self): - spec, subprocesses = self.load_workflow_spec('exclusive_non_default_path_into_multi.bpmn','ExclusiveNonDefaultMulti') - self.workflow = BpmnWorkflow(spec, subprocesses) - - def load_workflow1_spec(self): - return - - def testRunThroughHappy(self): - - - self.workflow.do_engine_steps() - - # Set initial array size to 3 in the first user form. - task = self.workflow.get_ready_user_tasks()[0] - self.assertEqual("DoStuff", task.task_spec.name) - task.update_data({"morestuff": 'Yes'}) - self.workflow.complete_task_from_id(task.id) - self.workflow.do_engine_steps() - - for i in range(3): - task = self.workflow.get_ready_user_tasks()[0] - if i == 0: - self.assertEqual("GetMoreStuff", task.task_spec.name) - else: - self.assertEqual("GetMoreStuff_%d"%(i-1), task.task_spec.name) - - - task.update_data({"stuff.addstuff": "Stuff %d"%i}) - self.workflow.complete_task_from_id(task.id) - self.workflow.do_engine_steps() - - self.assertTrue(self.workflow.is_completed()) - - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(ExclusiveGatewayNonDefaultPathIntoMultiTest) - -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/bpmn/IOSpecTest.py b/tests/SpiffWorkflow/bpmn/IOSpecTest.py index 6b27fc059..b3f70fe67 100644 --- a/tests/SpiffWorkflow/bpmn/IOSpecTest.py +++ b/tests/SpiffWorkflow/bpmn/IOSpecTest.py @@ -25,9 +25,6 @@ class CallActivityDataTest(BpmnWorkflowTestCase): with self.assertRaises(WorkflowDataException) as exc: self.advance_to_subprocess() - self.assertEqual("'in_2' was not found in the task data. " - "You are missing a required Data Input for a call activity.", - str(exc.exception)) self.assertEqual(exc.exception.data_input.name,'in_2') def testCallActivityMissingOutput(self): @@ -43,10 +40,7 @@ class CallActivityDataTest(BpmnWorkflowTestCase): with self.assertRaises(WorkflowDataException) as exc: self.complete_subprocess() - - self.assertEqual("'out_2' was not found in the task data. A Data Output was not provided as promised.", - str(exc.exception)) - self.assertEqual(exc.exception.data_output.name,'out_2') + self.assertEqual(exc.exception.data_output.name, 'out_2') def actual_test(self, save_restore=False): @@ -92,3 +86,44 @@ class CallActivityDataTest(BpmnWorkflowTestCase): next_task = self.workflow.get_tasks(TaskState.READY)[0] next_task.complete() waiting = self.workflow.get_tasks(TaskState.WAITING) + + +class IOSpecOnTaskTest(BpmnWorkflowTestCase): + + def setUp(self): + self.spec, self.subprocesses = self.load_workflow_spec('io_spec_on_task.bpmn', 'main') + + def testIOSpecOnTask(self): + self.actual_test() + + def testIOSpecOnTaskSaveRestore(self): + self.actual_test(True) + + def testIOSpecOnTaskMissingInput(self): + self.workflow = BpmnWorkflow(self.spec, self.subprocesses) + set_data = self.workflow.spec.task_specs['set_data'] + set_data.script = """in_1, unused = 1, True""" + with self.assertRaises(WorkflowDataException) as exc: + self.workflow.do_engine_steps() + self.assertEqual(exc.exception.data_input.name, 'in_2') + + def testIOSpecOnTaskMissingOutput(self): + self.workflow = BpmnWorkflow(self.spec, self.subprocesses) + self.workflow.do_engine_steps() + task = self.workflow.get_tasks_from_spec_name('any_task')[0] + task.data.update({'out_1': 1}) + with self.assertRaises(WorkflowDataException) as exc: + task.complete() + self.assertEqual(exc.exception.data_output.name, 'out_2') + + def actual_test(self, save_restore=False): + self.workflow = BpmnWorkflow(self.spec, self.subprocesses) + self.workflow.do_engine_steps() + if save_restore: + self.save_restore() + task = self.workflow.get_tasks_from_spec_name('any_task')[0] + self.assertDictEqual(task.data, {'in_1': 1, 'in_2': 'hello world'}) + task.data.update({'out_1': 1, 'out_2': 'bye', 'extra': True}) + task.complete() + self.workflow.do_engine_steps() + self.assertDictEqual(self.workflow.last_task.data, {'out_1': 1, 'out_2': 'bye'}) diff --git a/tests/SpiffWorkflow/bpmn/LoopTaskTest.py b/tests/SpiffWorkflow/bpmn/LoopTaskTest.py deleted file mode 100644 index 709750c64..000000000 --- a/tests/SpiffWorkflow/bpmn/LoopTaskTest.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- - -import unittest -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase - -__author__ = 'kellym' - - -class LoopTaskTest(BpmnWorkflowTestCase): - """The example bpmn diagram has a single task with a loop cardinality of 5. - It should repeat 5 times before termination.""" - - def setUp(self): - spec, subprocesses = self.load_workflow_spec('bpmnLoopTask.bpmn','LoopTaskTest') - self.workflow = BpmnWorkflow(spec, subprocesses) - - def testRunThroughHappy(self): - - for i in range(5): - self.workflow.do_engine_steps() - ready_tasks = self.workflow.get_ready_user_tasks() - self.assertTrue(len(ready_tasks) ==1) - self.assertTrue(ready_tasks[0].task_spec.is_loop_task()) - self.assertFalse(self.workflow.is_completed()) - last_task = self.workflow.last_task - - self.do_next_exclusive_step('Activity_TestLoop') - - ready_tasks = self.workflow.get_ready_user_tasks() - self.assertTrue(len(ready_tasks) ==1) - ready_tasks[0].terminate_loop() - self.do_next_exclusive_step('Activity_TestLoop') - self.workflow.do_engine_steps() - self.assertTrue(self.workflow.is_completed()) - - - def testSaveRestore(self): - - for i in range(5): - self.save_restore() - self.workflow.do_engine_steps() - ready_tasks = self.workflow.get_ready_user_tasks() - self.assertTrue(len(ready_tasks) ==1) - self.assertTrue(ready_tasks[0].task_spec.is_loop_task()) - self.assertFalse(self.workflow.is_completed()) - self.do_next_exclusive_step('Activity_TestLoop') - - ready_tasks = self.workflow.get_ready_user_tasks() - self.assertTrue(len(ready_tasks) ==1) - ready_tasks[0].terminate_loop() - self.do_next_exclusive_step('Activity_TestLoop') - self.workflow.do_engine_steps() - self.assertTrue(self.workflow.is_completed()) - - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(LoopTaskTest) -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/bpmn/MultiInstanceParallelCondTest.py b/tests/SpiffWorkflow/bpmn/MultiInstanceParallelCondTest.py deleted file mode 100644 index 305cb3df9..000000000 --- a/tests/SpiffWorkflow/bpmn/MultiInstanceParallelCondTest.py +++ /dev/null @@ -1,54 +0,0 @@ -# -*- coding: utf-8 -*- - -import sys -import os -import unittest -sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase - -__author__ = 'matth' - - -class MultiInstanceCondTest(BpmnWorkflowTestCase): - """The example bpmn diagram has a single task set to be a parallel - multi-instance with a loop cardinality of 5. - It should repeat 5 times before termination, and it should - have a navigation list with 7 items in it - one for start, one for end, - and five items for the repeating section. """ - - def setUp(self): - spec, subprocesses = self.load_workflow_spec('MultiInstanceParallelTaskCond.bpmn', 'MultiInstance') - self.workflow = BpmnWorkflow(spec, subprocesses) - - def load_workflow1_spec(self): - return - - def testRunThroughHappy(self): - self.actualTest() - - def testSaveRestore(self): - self.actualTest(True) - - def actualTest(self, save_restore=False): - - self.workflow.do_engine_steps() - self.assertEqual(1, len(self.workflow.get_ready_user_tasks())) - task = self.workflow.get_ready_user_tasks()[0] - task.data['collection'] = {'a':{'a':'test'}, - 'b':{'b':'test'}} - self.workflow.complete_task_from_id(task.id) - self.workflow.do_engine_steps() - - for task in self.workflow.get_ready_user_tasks(): - self.assertFalse(self.workflow.is_completed()) - self.workflow.complete_task_from_id(task.id) - if save_restore: - self.save_restore() - self.workflow.do_engine_steps() - self.assertTrue(self.workflow.is_completed()) - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(MultiInstanceCondTest) -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/bpmn/MultiInstanceParallelTest.py b/tests/SpiffWorkflow/bpmn/MultiInstanceParallelTest.py deleted file mode 100644 index e13b943a2..000000000 --- a/tests/SpiffWorkflow/bpmn/MultiInstanceParallelTest.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- coding: utf-8 -*- - -import sys -import os -import unittest -sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase - -__author__ = 'matth' - - -class MultiInstanceTest(BpmnWorkflowTestCase): - """The example bpmn diagram has a single task set to be a parallel - multi-instance with a loop cardinality of 5. - It should repeat 5 times before termination, and it should - have a navigation list with 7 items in it - one for start, one for end, - and five items for the repeating section. """ - - def setUp(self): - spec, subprocesses = self.load_workflow_spec('MultiInstanceParallelTask.bpmn', 'MultiInstance') - self.workflow = BpmnWorkflow(spec, subprocesses) - - def load_workflow1_spec(self): - return - - def testRunThroughHappy(self): - self.actualTest() - - def testSaveRestore(self): - self.actualTest(True) - - def actualTest(self, save_restore=False): - self.workflow.do_engine_steps() - self.assertEqual(1, len(self.workflow.get_ready_user_tasks())) - task = self.workflow.get_ready_user_tasks()[0] - task.data['collection'] = [1,2,3,4,5] - self.workflow.complete_task_from_id(task.id) - self.workflow.do_engine_steps() - for task in self.workflow.get_ready_user_tasks(): - self.assertFalse(self.workflow.is_completed()) - self.workflow.complete_task_from_id(task.id) - if save_restore: - self.save_restore() - self.workflow.do_engine_steps() - self.assertTrue(self.workflow.is_completed()) - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(MultiInstanceTest) -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/bpmn/MultiInstanceTest.py b/tests/SpiffWorkflow/bpmn/MultiInstanceTest.py deleted file mode 100644 index 6054f99a4..000000000 --- a/tests/SpiffWorkflow/bpmn/MultiInstanceTest.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- coding: utf-8 -*- - -import sys -import os -import unittest -sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase - -__author__ = 'matth' - - -class MultiInstanceTest(BpmnWorkflowTestCase): - """The example bpmn diagram has a single task with a loop cardinality of 5. - It should repeat 5 times before termination.""" - - def setUp(self): - spec, subprocesses = self.load_workflow_spec('bpmnMultiUserTask.bpmn','MultiInstance') - self.workflow = BpmnWorkflow(spec, subprocesses) - - - def testRunThroughHappy(self): - - for i in range(5): - self.workflow.do_engine_steps() - self.assertFalse(self.workflow.is_completed()) - self.do_next_exclusive_step('Activity_Loop') - - self.workflow.do_engine_steps() - self.assertTrue(self.workflow.is_completed()) - - def testSaveRestore(self): - - for i in range(5): - self.save_restore() - self.workflow.do_engine_steps() - self.assertFalse(self.workflow.is_completed()) - self.do_next_exclusive_step('Activity_Loop') - - self.workflow.do_engine_steps() - self.assertTrue(self.workflow.is_completed()) - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(MultiInstanceTest) -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/bpmn/ParallelMultiInstanceTest.py b/tests/SpiffWorkflow/bpmn/ParallelMultiInstanceTest.py new file mode 100644 index 000000000..c72948b42 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/ParallelMultiInstanceTest.py @@ -0,0 +1,233 @@ +from SpiffWorkflow.task import TaskState +from SpiffWorkflow.bpmn.exceptions import WorkflowDataException +from SpiffWorkflow.bpmn.workflow import BpmnWorkflow +from SpiffWorkflow.bpmn.specs.data_spec import TaskDataReference +from SpiffWorkflow.bpmn.parser.ValidationException import ValidationException + +from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase + + +class BaseTestCase(BpmnWorkflowTestCase): + + def set_io_and_run_workflow(self, data, data_input=None, data_output=None, save_restore=False): + + start = self.workflow.get_tasks_from_spec_name('Start')[0] + start.data = data + + any_task = self.workflow.get_tasks_from_spec_name('any_task')[0] + any_task.task_spec.data_input = TaskDataReference(data_input) if data_input is not None else None + any_task.task_spec.data_output = TaskDataReference(data_output) if data_output is not None else None + + self.workflow.do_engine_steps() + ready_tasks = self.workflow.get_ready_user_tasks() + self.assertEqual(len(ready_tasks), 3) + while len(ready_tasks) > 0: + task = ready_tasks[0] + self.assertEqual(task.task_spec.name, 'any_task [child]') + self.assertIn('input_item', task.data) + task.data['output_item'] = task.data['input_item'] * 2 + task.complete() + if save_restore: + self.save_restore() + ready_tasks = self.workflow.get_ready_user_tasks() + self.workflow.refresh_waiting_tasks() + self.workflow.do_engine_steps() + self.assertTrue(self.workflow.is_completed()) + + def run_workflow_with_condition(self, data): + + start = self.workflow.get_tasks_from_spec_name('Start')[0] + start.data = data + + task = self.workflow.get_tasks_from_spec_name('any_task')[0] + task.task_spec.condition = "input_item == 2" + + self.workflow.do_engine_steps() + ready_tasks = self.workflow.get_ready_user_tasks() + self.assertEqual(len(ready_tasks), 3) + task = [t for t in ready_tasks if t.data['input_item'] == 2][0] + task.data['output_item'] = task.data['input_item'] * 2 + task.complete() + self.workflow.do_engine_steps() + self.workflow.refresh_waiting_tasks() + + self.assertTrue(self.workflow.is_completed()) + self.assertEqual(len([ t for t in ready_tasks if t.state == TaskState.CANCELLED]), 2) + + +class ParallellMultiInstanceExistingOutputTest(BaseTestCase): + + def setUp(self): + self.spec, subprocess = self.load_workflow_spec('parallel_multiinstance_loop_input.bpmn', 'main') + self.workflow = BpmnWorkflow(self.spec) + + def testListWithDictOutput(self): + data = { + 'input_data': [1, 2, 3], + 'output_data': {}, + } + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data') + self.assertDictEqual(self.workflow.data, { + 'input_data': [1, 2, 3], + 'output_data': {0: 2, 1: 4, 2: 6}, + }) + + def testDictWithListOutput(self): + data = { + 'input_data': {'a': 1, 'b': 2, 'c': 3}, + 'output_data': [], + } + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data') + self.assertDictEqual(self.workflow.data, { + 'input_data': {'a': 1, 'b': 2, 'c': 3}, + 'output_data': [2, 4, 6], + }) + + def testNonEmptyOutput(self): + with self.assertRaises(WorkflowDataException) as exc: + data = { + 'input_data': [1, 2, 3], + 'output_data': [1, 2, 3], + } + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data') + self.assertEqual(exc.exception.message, + "If the input is not being updated in place, the output must be empty or it must be a map (dict)") + + def testInvalidOutputType(self): + with self.assertRaises(WorkflowDataException) as exc: + data = { + 'input_data': set([1, 2, 3]), + 'output_data': set(), + } + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data') + self.assertEqual(exc.exception.message, "Only a mutable map (dict) or sequence (list) can be used for output") + + +class ParallelMultiInstanceNewOutputTest(BaseTestCase): + + def setUp(self): + self.spec, subprocess = self.load_workflow_spec('parallel_multiinstance_loop_input.bpmn', 'main') + self.workflow = BpmnWorkflow(self.spec) + + def testList(self): + data = {'input_data': [1, 2, 3]} + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data') + self.assertDictEqual(self.workflow.data, { + 'input_data': [1, 2, 3], + 'output_data': [2, 4, 6] + }) + + def testListSaveRestore(self): + data = {'input_data': [1, 2, 3]} + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data', save_restore=True) + self.assertDictEqual(self.workflow.data, { + 'input_data': [1, 2, 3], + 'output_data': [2, 4, 6] + }) + + def testDict(self): + data = {'input_data': {'a': 1, 'b': 2, 'c': 3} } + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data') + self.assertDictEqual(self.workflow.data, { + 'input_data': {'a': 1, 'b': 2, 'c': 3}, + 'output_data': {'a': 2, 'b': 4, 'c': 6} + }) + + def testDictSaveRestore(self): + data = {'input_data': {'a': 1, 'b': 2, 'c': 3} } + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data', save_restore=True) + self.assertDictEqual(self.workflow.data, { + 'input_data': {'a': 1, 'b': 2, 'c': 3}, + 'output_data': {'a': 2, 'b': 4, 'c': 6} + }) + + def testSet(self): + data = {'input_data': set([1, 2, 3])} + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data') + self.assertDictEqual(self.workflow.data, { + 'input_data': set([1, 2, 3]), + 'output_data': [2, 4, 6] + }) + + def testEmptyCollection(self): + + start = self.workflow.get_tasks_from_spec_name('Start')[0] + start.data = {'input_data': []} + self.workflow.do_engine_steps() + self.assertTrue(self.workflow.is_completed()) + self.assertDictEqual(self.workflow.data, {'input_data': [], 'output_data': []}) + + def testCondition(self): + self.run_workflow_with_condition({'input_data': [1, 2, 3]}) + self.assertDictEqual(self.workflow.data, { + 'input_data': [1, 2, 3], + 'output_data': [4] + }) + + +class ParallelMultiInstanceUpdateInputTest(BaseTestCase): + + def setUp(self): + self.spec, subprocess = self.load_workflow_spec('parallel_multiinstance_loop_input.bpmn', 'main') + self.workflow = BpmnWorkflow(self.spec) + + def testList(self): + data = { 'input_data': [1, 2, 3]} + self.set_io_and_run_workflow(data, data_input='input_data', data_output='input_data') + self.assertDictEqual(self.workflow.data, {'input_data': [2, 4, 6]}) + + def testDict(self): + data = { 'input_data': {'a': 1, 'b': 2, 'c': 3}} + self.set_io_and_run_workflow(data, data_input='input_data', data_output='input_data') + self.assertDictEqual(self.workflow.data, {'input_data': {'a': 2, 'b': 4, 'c': 6}}) + + +class ParallelMultiInstanceWithCardinality(BaseTestCase): + + def setUp(self) -> None: + self.spec, subprocess = self.load_workflow_spec('parallel_multiinstance_cardinality.bpmn', 'main') + self.workflow = BpmnWorkflow(self.spec) + + def testCardinality(self): + self.set_io_and_run_workflow({}, data_output='output_data') + self.assertDictEqual(self.workflow.data, {'output_data': [0, 2, 4]}) + + def testCardinalitySaveRestore(self): + self.set_io_and_run_workflow({}, data_output='output_data', save_restore=True) + self.assertDictEqual(self.workflow.data, {'output_data': [0, 2, 4]}) + + def testCondition(self): + self.run_workflow_with_condition({}) + self.assertDictEqual(self.workflow.data, { + 'output_data': [4] + }) + + +class ParallelMultiInstanceTaskTest(BpmnWorkflowTestCase): + + def check_reference(self, reference, name): + self.assertIsInstance(reference, TaskDataReference) + self.assertEqual(reference.name, name) + + def testParseInputOutput(self): + spec, subprocess = self.load_workflow_spec('parallel_multiinstance_loop_input.bpmn', 'main') + workflow = BpmnWorkflow(spec) + task_spec = workflow.get_tasks_from_spec_name('any_task')[0].task_spec + self.check_reference(task_spec.data_input, 'input_data') + self.check_reference(task_spec.data_output, 'output_data') + self.check_reference(task_spec.input_item, 'input_item') + self.check_reference(task_spec.output_item, 'output_item') + self.assertIsNone(task_spec.cardinality) + + def testParseCardinality(self): + spec, subprocess = self.load_workflow_spec('parallel_multiinstance_cardinality.bpmn', 'main') + workflow = BpmnWorkflow(spec) + task_spec = workflow.get_tasks_from_spec_name('any_task')[0].task_spec + self.assertIsNone(task_spec.data_input) + self.assertEqual(task_spec.cardinality, '3') + + def testInvalidBpmn(self): + with self.assertRaises(ValidationException) as exc: + spec, subprocess = self.load_workflow_spec('parallel_multiinstance_invalid.bpmn', 'main') + self.assertEqual(exc.exception.message, + 'A multiinstance task must specify exactly one of cardinality or loop input data reference.') diff --git a/tests/SpiffWorkflow/bpmn/ParallelOrderTest.py b/tests/SpiffWorkflow/bpmn/ParallelOrderTest.py index 67d3c90bd..39797448b 100644 --- a/tests/SpiffWorkflow/bpmn/ParallelOrderTest.py +++ b/tests/SpiffWorkflow/bpmn/ParallelOrderTest.py @@ -1,16 +1,12 @@ # -*- coding: utf-8 -*- -import sys -import os import unittest -sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) + from SpiffWorkflow.bpmn.workflow import BpmnWorkflow from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase -__author__ = 'matth' - -class MultiInstanceTest(BpmnWorkflowTestCase): +class ParallelOrderTest(BpmnWorkflowTestCase): """The example bpmn diagram has a 4 parallel workflows, this verifies that the parallel tasks have a natural order that follows the visual layout of the diagram, rather than just the order in which @@ -33,6 +29,6 @@ class MultiInstanceTest(BpmnWorkflowTestCase): def suite(): - return unittest.TestLoader().loadTestsFromTestCase(MultiInstanceTest) + return unittest.TestLoader().loadTestsFromTestCase(ParallelOrderTest) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/bpmn/ParallelWithScriptTest.py b/tests/SpiffWorkflow/bpmn/ParallelWithScriptTest.py deleted file mode 100644 index 933d8a91d..000000000 --- a/tests/SpiffWorkflow/bpmn/ParallelWithScriptTest.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- - - - -import unittest -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase - -__author__ = 'leashys' - - -class ParallelWithScriptTest(BpmnWorkflowTestCase): - - def setUp(self): - spec, subprocesses = self.load_workflow_spec('ParallelWithScript.bpmn', 'ParallelWithScript') - self.workflow = BpmnWorkflow(spec, subprocesses) - - def testRunThroughParallel(self): - self.workflow.do_engine_steps() - # TODO: what to assert here? - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(ParallelWithScriptTest) -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/bpmn/ParserTest.py b/tests/SpiffWorkflow/bpmn/ParserTest.py index 59a327758..25d26fdb6 100644 --- a/tests/SpiffWorkflow/bpmn/ParserTest.py +++ b/tests/SpiffWorkflow/bpmn/ParserTest.py @@ -13,8 +13,8 @@ class ParserTest(unittest.TestCase): bpmn_file = os.path.join(os.path.dirname(__file__), 'data', 'io_spec.bpmn') parser.add_bpmn_file(bpmn_file) spec = parser.get_spec('subprocess') - self.assertEqual(len(spec.data_inputs), 2) - self.assertEqual(len(spec.data_outputs), 2) + self.assertEqual(len(spec.io_specification.data_inputs), 2) + self.assertEqual(len(spec.io_specification.data_outputs), 2) def testDataReferences(self): diff --git a/tests/SpiffWorkflow/bpmn/ResetTimerTest.py b/tests/SpiffWorkflow/bpmn/ResetTimerTest.py new file mode 100644 index 000000000..8a94dabab --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/ResetTimerTest.py @@ -0,0 +1,28 @@ + +from SpiffWorkflow.bpmn.workflow import BpmnWorkflow +from SpiffWorkflow.task import TaskState + +from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase + +class ResetTimerTest(BpmnWorkflowTestCase): + + def test_timer(self): + spec, subprocess = self.load_workflow_spec('reset_timer.bpmn', 'main') + self.workflow = BpmnWorkflow(spec, subprocess) + self.workflow.do_engine_steps() + task_1 = self.workflow.get_tasks_from_spec_name('task_1')[0] + timer = self.workflow.get_tasks_from_spec_name('timer')[0] + original_timer = timer.internal_data.get('event_value') + # This returns us to the task + task_1.data['modify'] = True + task_1.complete() + self.workflow.do_engine_steps() + # The timer should be waiting and the time should have been updated + self.assertEqual(task_1.state, TaskState.READY) + self.assertEqual(timer.state, TaskState.WAITING) + self.assertGreater(timer.internal_data.get('event_value'), original_timer) + task_1.data['modify'] = False + task_1.complete() + self.workflow.do_engine_steps() + self.assertEqual(timer.state, TaskState.CANCELLED) + self.assertTrue(self.workflow.is_completed()) \ No newline at end of file diff --git a/tests/SpiffWorkflow/bpmn/SequentialMultiInstanceTest.py b/tests/SpiffWorkflow/bpmn/SequentialMultiInstanceTest.py new file mode 100644 index 000000000..ba93fdbe1 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/SequentialMultiInstanceTest.py @@ -0,0 +1,213 @@ +from SpiffWorkflow.task import TaskState +from SpiffWorkflow.bpmn.exceptions import WorkflowDataException +from SpiffWorkflow.bpmn.workflow import BpmnWorkflow +from SpiffWorkflow.bpmn.specs.data_spec import TaskDataReference + +from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase + + +class BaseTestCase(BpmnWorkflowTestCase): + + def set_io_and_run_workflow(self, data, data_input=None, data_output=None, save_restore=False): + + start = self.workflow.get_tasks_from_spec_name('Start')[0] + start.data = data + + any_task = self.workflow.get_tasks_from_spec_name('any_task')[0] + any_task.task_spec.data_input = TaskDataReference(data_input) if data_input is not None else None + any_task.task_spec.data_output = TaskDataReference(data_output) if data_output is not None else None + + self.workflow.do_engine_steps() + self.workflow.refresh_waiting_tasks() + ready_tasks = self.workflow.get_ready_user_tasks() + + while len(ready_tasks) > 0: + self.assertEqual(len(ready_tasks), 1) + task = ready_tasks[0] + self.assertEqual(task.task_spec.name, 'any_task [child]') + self.assertIn('input_item', task.data) + task.data['output_item'] = task.data['input_item'] * 2 + task.complete() + if save_restore: + self.save_restore() + ready_tasks = self.workflow.get_ready_user_tasks() + + self.workflow.do_engine_steps() + children = self.workflow.get_tasks_from_spec_name('any_task [child]') + self.assertEqual(len(children), 3) + self.assertTrue(self.workflow.is_completed()) + + def run_workflow_with_condition(self, data, condition): + + start = self.workflow.get_tasks_from_spec_name('Start')[0] + start.data = data + + task = self.workflow.get_tasks_from_spec_name('any_task')[0] + task.task_spec.condition = condition + + self.workflow.do_engine_steps() + self.workflow.refresh_waiting_tasks() + ready_tasks = self.workflow.get_ready_user_tasks() + + while len(ready_tasks) > 0: + ready = ready_tasks[0] + self.assertEqual(ready.task_spec.name, 'any_task [child]') + self.assertIn('input_item', ready.data) + ready.data['output_item'] = ready.data['input_item'] * 2 + ready.complete() + self.workflow.do_engine_steps() + self.workflow.refresh_waiting_tasks() + ready_tasks = self.workflow.get_ready_user_tasks() + + self.workflow.do_engine_steps() + children = self.workflow.get_tasks_from_spec_name('any_task [child]') + self.assertEqual(len(children), 2) + self.assertTrue(self.workflow.is_completed()) + + +class SequentialMultiInstanceExistingOutputTest(BaseTestCase): + + def setUp(self): + self.spec, subprocess = self.load_workflow_spec('sequential_multiinstance_loop_input.bpmn', 'main') + self.workflow = BpmnWorkflow(self.spec) + + def testListWithDictOutput(self): + data = { + 'input_data': [1, 2, 3], + 'output_data': {}, + } + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data') + self.assertDictEqual(self.workflow.data, { + 'input_data': [1, 2, 3], + 'output_data': {0: 2, 1: 4, 2: 6}, + }) + + def testDictWithListOutput(self): + data = { + 'input_data': {'a': 1, 'b': 2, 'c': 3}, + 'output_data': [], + } + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data') + self.assertDictEqual(self.workflow.data, { + 'input_data': {'a': 1, 'b': 2, 'c': 3}, + 'output_data': [2, 4, 6], + }) + + def testNonEmptyOutput(self): + with self.assertRaises(WorkflowDataException) as exc: + data = { + 'input_data': [1, 2, 3], + 'output_data': [1, 2, 3], + } + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data') + self.assertEqual(exc.exception.message, + "If the input is not being updated in place, the output must be empty or it must be a map (dict)") + + def testInvalidOutputType(self): + with self.assertRaises(WorkflowDataException) as exc: + data = { + 'input_data': set([1, 2, 3]), + 'output_data': set(), + } + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data') + self.assertEqual(exc.exception.message, "Only a mutable map (dict) or sequence (list) can be used for output") + + +class SequentialMultiInstanceNewOutputTest(BaseTestCase): + + def setUp(self): + self.spec, subprocess = self.load_workflow_spec('sequential_multiinstance_loop_input.bpmn', 'main') + self.workflow = BpmnWorkflow(self.spec) + + def testList(self): + data = {'input_data': [1, 2, 3]} + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data') + self.assertDictEqual(self.workflow.data, { + 'input_data': [1, 2, 3], + 'output_data': [2, 4, 6] + }) + + def testListSaveRestore(self): + data = {'input_data': [1, 2, 3]} + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data', save_restore=True) + self.assertDictEqual(self.workflow.data, { + 'input_data': [1, 2, 3], + 'output_data': [2, 4, 6] + }) + + def testDict(self): + data = {'input_data': {'a': 1, 'b': 2, 'c': 3} } + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data') + self.assertDictEqual(self.workflow.data, { + 'input_data': {'a': 1, 'b': 2, 'c': 3}, + 'output_data': {'a': 2, 'b': 4, 'c': 6} + }) + + def testDictSaveRestore(self): + data = {'input_data': {'a': 1, 'b': 2, 'c': 3} } + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data', save_restore=True) + self.assertDictEqual(self.workflow.data, { + 'input_data': {'a': 1, 'b': 2, 'c': 3}, + 'output_data': {'a': 2, 'b': 4, 'c': 6} + }) + + def testSet(self): + data = {'input_data': set([1, 2, 3])} + self.set_io_and_run_workflow(data, data_input='input_data', data_output='output_data') + self.assertDictEqual(self.workflow.data, { + 'input_data': set([1, 2, 3]), + 'output_data': [2, 4, 6] + }) + + def testEmptyCollection(self): + + start = self.workflow.get_tasks_from_spec_name('Start')[0] + start.data = {'input_data': []} + self.workflow.do_engine_steps() + self.assertTrue(self.workflow.is_completed()) + self.assertDictEqual(self.workflow.data, {'input_data': [], 'output_data': []}) + + def testCondition(self): + self.run_workflow_with_condition({'input_data': [1, 2, 3]}, "input_item == 2") + self.assertDictEqual(self.workflow.data, { + 'input_data': [1, 2, 3], + 'output_data': [2, 4] + }) + + +class SequentialMultiInstanceUpdateInputTest(BaseTestCase): + + def setUp(self): + self.spec, subprocess = self.load_workflow_spec('sequential_multiinstance_loop_input.bpmn', 'main') + self.workflow = BpmnWorkflow(self.spec) + + def testList(self): + data = { 'input_data': [1, 2, 3]} + self.set_io_and_run_workflow(data, data_input='input_data', data_output='input_data') + self.assertDictEqual(self.workflow.data, {'input_data': [2, 4, 6]}) + + def testDict(self): + data = { 'input_data': {'a': 1, 'b': 2, 'c': 3}} + self.set_io_and_run_workflow(data, data_input='input_data', data_output='input_data') + self.assertDictEqual(self.workflow.data, {'input_data': {'a': 2, 'b': 4, 'c': 6}}) + + +class SequentialMultiInstanceWithCardinality(BaseTestCase): + + def setUp(self) -> None: + self.spec, subprocess = self.load_workflow_spec('sequential_multiinstance_cardinality.bpmn', 'main') + self.workflow = BpmnWorkflow(self.spec) + + def testCardinality(self): + self.set_io_and_run_workflow({}, data_output='output_data') + self.assertDictEqual(self.workflow.data, {'output_data': [0, 2, 4]}) + + def testCardinalitySaveRestore(self): + self.set_io_and_run_workflow({}, data_output='output_data', save_restore=True) + self.assertDictEqual(self.workflow.data, {'output_data': [0, 2, 4]}) + + def testCondition(self): + self.run_workflow_with_condition({}, "input_item == 1") + self.assertDictEqual(self.workflow.data, { + 'output_data': [0, 2] + }) diff --git a/tests/SpiffWorkflow/bpmn/StandardLoopTest.py b/tests/SpiffWorkflow/bpmn/StandardLoopTest.py new file mode 100644 index 000000000..e9d6534c4 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/StandardLoopTest.py @@ -0,0 +1,62 @@ +import os + +from SpiffWorkflow.bpmn.workflow import BpmnWorkflow +from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnParser, ValidationException +from .BpmnWorkflowTestCase import BpmnWorkflowTestCase + +class StandardLoopTest(BpmnWorkflowTestCase): + + def setUp(self): + spec, subprocesses = self.load_workflow_spec('standard_loop.bpmn','main', validate=False) + # This spec has a loop task with loopMaximum = 3 and loopCondition = 'done' + self.workflow = BpmnWorkflow(spec, subprocesses) + + def testLoopMaximum(self): + + start = self.workflow.get_tasks_from_spec_name('StartEvent_1') + start[0].data['done'] = False + for idx in range(3): + self.workflow.do_engine_steps() + self.workflow.refresh_waiting_tasks() + ready_tasks = self.workflow.get_ready_user_tasks() + self.assertEqual(len(ready_tasks), 1) + ready_tasks[0].data[str(idx)] = True + ready_tasks[0].complete() + + self.workflow.do_engine_steps() + self.assertTrue(self.workflow.is_completed()) + + def testLoopCondition(self): + + start = self.workflow.get_tasks_from_spec_name('StartEvent_1') + start[0].data['done'] = False + + self.workflow.do_engine_steps() + self.workflow.refresh_waiting_tasks() + ready_tasks = self.workflow.get_ready_user_tasks() + self.assertEqual(len(ready_tasks), 1) + ready_tasks[0].data['done'] = True + ready_tasks[0].complete() + + self.workflow.do_engine_steps() + self.assertTrue(self.workflow.is_completed()) + + def testSkipLoop(self): + + # This is called "skip loop" because I thought "testTestBefore" was a terrible name + start = self.workflow.get_tasks_from_spec_name('StartEvent_1') + start[0].data['done'] = True + self.workflow.do_engine_steps() + self.workflow.refresh_waiting_tasks() + self.workflow.do_engine_steps() + self.assertTrue(self.workflow.is_completed()) + + +class ParseStandardLoop(BpmnWorkflowTestCase): + + def testParseStandardLoop(self): + parser = BpmnParser() + # This process has neither a loop condition nor a loop maximum + bpmn_file = os.path.join(os.path.dirname(__file__), 'data', 'standard_loop_invalid.bpmn') + parser.add_bpmn_file(bpmn_file) + self.assertRaises(ValidationException, parser.get_spec, 'main') diff --git a/tests/SpiffWorkflow/bpmn/SubWorkflowMultiTest.py b/tests/SpiffWorkflow/bpmn/SubWorkflowMultiTest.py deleted file mode 100644 index 83dfcef26..000000000 --- a/tests/SpiffWorkflow/bpmn/SubWorkflowMultiTest.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- coding: utf-8 -*- - -import unittest - -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase - -__author__ = 'matth' - - -class SubWorkflowMultiTest(BpmnWorkflowTestCase): - - expected_data = { - 'a': {'name': 'Apple_edit', - 'new_info': 'Adding this!'}, - 'b': {'name': 'Bubble_edit', - 'new_info': 'Adding this!'}, - 'c': {'name': 'Crap, I should write better code_edit', - 'new_info': 'Adding this!'} - } - - def testSequential(self): - spec, subprocesses = self.load_workflow_spec('sub_workflow_multi.bpmn', 'ScriptTest') - self.workflow = BpmnWorkflow(spec, subprocesses) - self.workflow.do_engine_steps() - - data = self.workflow.last_task.data - self.assertEqual(data['my_collection'], self.expected_data) - - def testParallel(self): - spec, subprocesses= self.load_workflow_spec('sub_workflow_multi_parallel.bpmn', 'ScriptTest') - self.workflow = BpmnWorkflow(spec, subprocesses) - self.workflow.do_engine_steps() - - data = self.workflow.last_task.data - self.assertEqual(data['my_collection'], self.expected_data) - - def testWrapped(self): - spec, subprocesses = self.load_workflow_spec('sub_within_sub_multi.bpmn', 'ScriptTest') - self.workflow = BpmnWorkflow(spec, subprocesses) - self.workflow.do_engine_steps() - - data = self.workflow.last_task.data - self.assertEqual(self.expected_data, data['my_collection']) - - - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(SubWorkflowMultiTest) -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/bpmn/data/MultiInstanceParallelTask.bpmn b/tests/SpiffWorkflow/bpmn/data/MultiInstanceParallelTask.bpmn deleted file mode 100644 index 6b02f0961..000000000 --- a/tests/SpiffWorkflow/bpmn/data/MultiInstanceParallelTask.bpmn +++ /dev/null @@ -1,59 +0,0 @@ - - - - - Flow_0t6p1sb - - - - Flow_0ugjw69 - - - - Flow_0ds4mp0 - Flow_0ugjw69 - - collection - - - - Flow_0t6p1sb - Flow_0ds4mp0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/bpmn/data/MultiInstanceParallelTaskCond.bpmn b/tests/SpiffWorkflow/bpmn/data/MultiInstanceParallelTaskCond.bpmn deleted file mode 100644 index 53ecfd4e2..000000000 --- a/tests/SpiffWorkflow/bpmn/data/MultiInstanceParallelTaskCond.bpmn +++ /dev/null @@ -1,145 +0,0 @@ - - - - - Flow_0t6p1sb - - - - Flow_0ugjw69 - Flow_1oo4mpj - - - - Flow_0u92n7b - Flow_0ugjw69 - - - - Flow_0t6p1sb - Flow_0ds4mp0 - - - - Flow_1sx7n9u - Flow_1oo4mpj - Flow_0u92n7b - - - len(collection.keys())==0 - - - - - Flow_0ds4mp0 - Flow_1dah8xt - Flow_0i1bv5g - - - - Flow_1dah8xt - Flow_0io0g18 - - - Flow_0io0g18 - Flow_0i1bv5g - Flow_1sx7n9u - - - - 1==1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/bpmn/data/ParallelWithScript.bpmn b/tests/SpiffWorkflow/bpmn/data/ParallelWithScript.bpmn deleted file mode 100644 index a92df4add..000000000 --- a/tests/SpiffWorkflow/bpmn/data/ParallelWithScript.bpmn +++ /dev/null @@ -1,117 +0,0 @@ - - - - - Flow_1swtnkk - - - - - - - - - - - Flow_1empxbr - Flow_1m1yz1x - # do nothing - - - Flow_04k0ue9 - - - - Flow_1swtnkk - Flow_1ukvcj0 - Flow_188f01l - Flow_1empxbr - - - Flow_0ykkbts - Flow_0lmf2gd - Flow_0954wrk - Flow_04k0ue9 - - - Flow_1ukvcj0 - Flow_0lmf2gd - - - Flow_188f01l - Flow_0ykkbts - - - Flow_1m1yz1x - Flow_0954wrk - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/bpmn/data/bpmnAntiLoopTask.bpmn b/tests/SpiffWorkflow/bpmn/data/bpmnAntiLoopTask.bpmn deleted file mode 100644 index 4893f713a..000000000 --- a/tests/SpiffWorkflow/bpmn/data/bpmnAntiLoopTask.bpmn +++ /dev/null @@ -1,47 +0,0 @@ - - - - - Flow_0q33jmj - - - Enter Name for member {{ Activity_TestLoop_CurrentVar }} - - - - - - Flow_0q33jmj - Flow_13213ce - - 5 - - - - - Flow_13213ce - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/bpmn/data/bpmnLoopTask.bpmn b/tests/SpiffWorkflow/bpmn/data/bpmnLoopTask.bpmn deleted file mode 100644 index c35b237e2..000000000 --- a/tests/SpiffWorkflow/bpmn/data/bpmnLoopTask.bpmn +++ /dev/null @@ -1,45 +0,0 @@ - - - - - Flow_0q33jmj - - - Enter Name for member {{ Activity_TestLoop_CurrentVar }} - - - - - - Flow_0q33jmj - Flow_13213ce - - - - - Flow_13213ce - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/bpmn/data/bpmnMultiUserTask.bpmn b/tests/SpiffWorkflow/bpmn/data/bpmnMultiUserTask.bpmn deleted file mode 100644 index d9a723161..000000000 --- a/tests/SpiffWorkflow/bpmn/data/bpmnMultiUserTask.bpmn +++ /dev/null @@ -1,49 +0,0 @@ - - - - - Flow_0t6p1sb - - - - Flow_0ugjw69 - - - - Flow_0t6p1sb - Flow_0ugjw69 - - 5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/bpmn/data/data_object.bpmn b/tests/SpiffWorkflow/bpmn/data/data_object.bpmn index 298c5fa2f..c558cf59d 100644 --- a/tests/SpiffWorkflow/bpmn/data/data_object.bpmn +++ b/tests/SpiffWorkflow/bpmn/data/data_object.bpmn @@ -11,6 +11,7 @@ + Flow_19pyf8s @@ -38,17 +39,20 @@ Flow_1tnu3ej Flow_19pyf8s - - - DataObjectReference_0cm8dnh - Property_1q5wp77 - Flow_0yx8lkz Flow_0yx8lkz Flow_0rk4i35 + + + DataObjectReference_0cm8dnh + Property_1q5wp77 + + + DataObjectReference_1dn9eoi + diff --git a/tests/SpiffWorkflow/bpmn/data/data_store.bpmn b/tests/SpiffWorkflow/bpmn/data/data_store.bpmn new file mode 100644 index 000000000..1bc17744d --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/data_store.bpmn @@ -0,0 +1,89 @@ + + + + + + Flow_0oekyeq + + + + Flow_0mc5gib + + + + + + Flow_0oekyeq + Flow_0ah5fbf + + referenceToDataStore + + variableTiedToDataStore = "Sue" + + + Flow_0ah5fbf + Flow_0mtq2q5 + True + + + Flow_0mtq2q5 + Flow_0mc5gib + + + referenceToDataStore + Property_1k6jy2l + + x=variableTiedToDataStore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/bpmn/data/data_store_read.bpmn b/tests/SpiffWorkflow/bpmn/data/data_store_read.bpmn new file mode 100644 index 000000000..2ebed2652 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/data_store_read.bpmn @@ -0,0 +1,91 @@ + + + + + + Flow_0oekyeq + + + + Flow_0mc5gib + + + + + + Flow_0oekyeq + Flow_0ah5fbf + + True + + + Flow_0ah5fbf + Flow_0mtq2q5 + True + + + Flow_0mtq2q5 + Flow_0mc5gib + + + referenceToDataStore + Property_1k6jy2l + + x=variableTiedToDataStore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/bpmn/data/data_store_write.bpmn b/tests/SpiffWorkflow/bpmn/data/data_store_write.bpmn new file mode 100644 index 000000000..2453a21e8 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/data_store_write.bpmn @@ -0,0 +1,91 @@ + + + + + + Flow_0oekyeq + + + + Flow_0mc5gib + + + + + + Flow_0oekyeq + Flow_0ah5fbf + + referenceToDataStore + + variableTiedToDataStore = "Sue" + + + Flow_0ah5fbf + Flow_0mtq2q5 + True + + + Flow_0mtq2q5 + Flow_0mc5gib + + + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/bpmn/data/exclusive_into_multi.bpmn b/tests/SpiffWorkflow/bpmn/data/exclusive_into_multi.bpmn deleted file mode 100644 index 0fb12a411..000000000 --- a/tests/SpiffWorkflow/bpmn/data/exclusive_into_multi.bpmn +++ /dev/null @@ -1,83 +0,0 @@ - - - - - Flow_163toj3 - - - Flow_163toj3 - Flow_1rakb4c - x = 0 - - - - Flow_1rakb4c - Flow_04bjhw6 - Flow_0340se7 - - - - x != 0 - - - - - Flow_04bjhw6 - Flow_073oado - - 1 - - - - Flow_073oado - Flow_0340se7 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/bpmn/data/exclusive_non_default_path_into_multi.bpmn b/tests/SpiffWorkflow/bpmn/data/exclusive_non_default_path_into_multi.bpmn deleted file mode 100644 index bb4bbab0d..000000000 --- a/tests/SpiffWorkflow/bpmn/data/exclusive_non_default_path_into_multi.bpmn +++ /dev/null @@ -1,97 +0,0 @@ - - - - - Flow_0rqubl2 - - - - - - - - Flow_0rqubl2 - Flow_02orejl - - - Flow_02orejl - Flow_Yes - Flow_No - - - Flow_No - Flow_0pud9db - - - - - - - - Flow_Yes - Flow_0pud9db - - 3 - - - - - - morestuff == 'Yes' - - - morestuff == 'No' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/bpmn/data/io_spec.bpmn b/tests/SpiffWorkflow/bpmn/data/io_spec.bpmn index dc10332f0..773f11bca 100644 --- a/tests/SpiffWorkflow/bpmn/data/io_spec.bpmn +++ b/tests/SpiffWorkflow/bpmn/data/io_spec.bpmn @@ -13,8 +13,8 @@ as a required set of inputs or outputs that must all appear together --> - id_1 - id_2 + in_1 + in_2 out_1 @@ -85,4 +85,4 @@ - + \ No newline at end of file diff --git a/tests/SpiffWorkflow/bpmn/data/io_spec_on_task.bpmn b/tests/SpiffWorkflow/bpmn/data/io_spec_on_task.bpmn new file mode 100644 index 000000000..af89b3538 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/io_spec_on_task.bpmn @@ -0,0 +1,66 @@ + + + + + Flow_0zbeoq1 + + + + Flow_0zbeoq1 + Flow_16rr3p3 + in_1, in_2, unused = 1, "hello world", True + + + + + Flow_16rr3p3 + Flow_1woo38x + + + + + + + in_1 + in_2 + + + out_1 + out_2 + + + + + Flow_1woo38x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/bpmn/data/parallel_multiinstance_cardinality.bpmn b/tests/SpiffWorkflow/bpmn/data/parallel_multiinstance_cardinality.bpmn new file mode 100644 index 000000000..1f0e75b51 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/parallel_multiinstance_cardinality.bpmn @@ -0,0 +1,44 @@ + + + + + Flow_0m77cxj + + + Flow_0m77cxj + Flow_1jbp2el + + 3 + output_data + + + + + + + Flow_1jbp2el + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/bpmn/data/parallel_multiinstance_invalid.bpmn b/tests/SpiffWorkflow/bpmn/data/parallel_multiinstance_invalid.bpmn new file mode 100644 index 000000000..1113dd90d --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/parallel_multiinstance_invalid.bpmn @@ -0,0 +1,45 @@ + + + + + Flow_0m77cxj + + + Flow_0m77cxj + Flow_1jbp2el + + 3 + input_data + output_data + + + + + + + Flow_1jbp2el + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/bpmn/data/parallel_multiinstance_loop_input.bpmn b/tests/SpiffWorkflow/bpmn/data/parallel_multiinstance_loop_input.bpmn new file mode 100644 index 000000000..e9cce84e5 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/parallel_multiinstance_loop_input.bpmn @@ -0,0 +1,44 @@ + + + + + Flow_0m77cxj + + + Flow_0m77cxj + Flow_1jbp2el + + input_data + output_data + + + + + + + Flow_1jbp2el + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/bpmn/data/reset_timer.bpmn b/tests/SpiffWorkflow/bpmn/data/reset_timer.bpmn new file mode 100644 index 000000000..7750e4bb2 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/reset_timer.bpmn @@ -0,0 +1,104 @@ + + + + + Flow_0j648np + + + Flow_0j648np + modify + Flow_13cp5nc + + + + Flow_13cp5nc + Flow_1r81vou + + + + Flow_0m5s7t9 + Flow_0p7c88x + + + Flow_1gm7381 + Flow_0p7c88x + + + Flow_0m5s7t9 + + "PT60S" + + + + + Flow_1r81vou + modify + Flow_1gm7381 + + + + modify + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/bpmn/data/sequential_multiinstance_cardinality.bpmn b/tests/SpiffWorkflow/bpmn/data/sequential_multiinstance_cardinality.bpmn new file mode 100644 index 000000000..0271b3aef --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/sequential_multiinstance_cardinality.bpmn @@ -0,0 +1,44 @@ + + + + + Flow_0m77cxj + + + Flow_0m77cxj + Flow_1jbp2el + + 3 + output_data + + + + + + + Flow_1jbp2el + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/bpmn/data/sequential_multiinstance_loop_input.bpmn b/tests/SpiffWorkflow/bpmn/data/sequential_multiinstance_loop_input.bpmn new file mode 100644 index 000000000..a77f86b5f --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/sequential_multiinstance_loop_input.bpmn @@ -0,0 +1,44 @@ + + + + + Flow_0m77cxj + + + Flow_0m77cxj + Flow_1jbp2el + + input_data + output_data + + + + + + + Flow_1jbp2el + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/bpmn/data/serialization/v1.1-data.json b/tests/SpiffWorkflow/bpmn/data/serialization/v1.1-data.json new file mode 100644 index 000000000..796f58471 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/serialization/v1.1-data.json @@ -0,0 +1,731 @@ +{ + "serializer_version": "1.1", + "data": { + "obj_1": "object 1" + }, + "last_task": "9a4925a1-a152-428e-a764-b24d81b3cfdd", + "success": true, + "tasks": { + "4a2e2ad3-ad4b-4168-800d-71e31f33e225": { + "id": "4a2e2ad3-ad4b-4168-800d-71e31f33e225", + "parent": null, + "children": [ + "b666abf3-1e97-49c0-94b3-6e0f1a5573ec" + ], + "last_state_change": 1675380199.2266004, + "state": 32, + "task_spec": "Root", + "triggered": false, + "workflow_name": "parent", + "internal_data": {}, + "data": {} + }, + "b666abf3-1e97-49c0-94b3-6e0f1a5573ec": { + "id": "b666abf3-1e97-49c0-94b3-6e0f1a5573ec", + "parent": "4a2e2ad3-ad4b-4168-800d-71e31f33e225", + "children": [ + "c066bd8f-894d-4b24-b724-8c63fb15bdbf" + ], + "last_state_change": 1675380199.2330534, + "state": 32, + "task_spec": "Start", + "triggered": false, + "workflow_name": "parent", + "internal_data": {}, + "data": {} + }, + "c066bd8f-894d-4b24-b724-8c63fb15bdbf": { + "id": "c066bd8f-894d-4b24-b724-8c63fb15bdbf", + "parent": "b666abf3-1e97-49c0-94b3-6e0f1a5573ec", + "children": [ + "9a4925a1-a152-428e-a764-b24d81b3cfdd" + ], + "last_state_change": 1675380199.2362425, + "state": 32, + "task_spec": "Event_0xiw3t6", + "triggered": false, + "workflow_name": "parent", + "internal_data": { + "event_fired": true + }, + "data": {} + }, + "9a4925a1-a152-428e-a764-b24d81b3cfdd": { + "id": "9a4925a1-a152-428e-a764-b24d81b3cfdd", + "parent": "c066bd8f-894d-4b24-b724-8c63fb15bdbf", + "children": [ + "dcd54745-3143-4b4d-b557-f9c8ce9c7e71" + ], + "last_state_change": 1675380199.238688, + "state": 32, + "task_spec": "Activity_0haob58", + "triggered": false, + "workflow_name": "parent", + "internal_data": {}, + "data": { + "in_1": 1, + "in_2": "hello world", + "unused": true + } + }, + "dcd54745-3143-4b4d-b557-f9c8ce9c7e71": { + "id": "dcd54745-3143-4b4d-b557-f9c8ce9c7e71", + "parent": "9a4925a1-a152-428e-a764-b24d81b3cfdd", + "children": [ + "3a537753-2578-4f33-914c-5e840d2f9612" + ], + "last_state_change": 1675380199.243926, + "state": 8, + "task_spec": "Activity_1wdjypm", + "triggered": false, + "workflow_name": "parent", + "internal_data": {}, + "data": { + "in_1": 1, + "in_2": "hello world", + "unused": true + } + }, + "3a537753-2578-4f33-914c-5e840d2f9612": { + "id": "3a537753-2578-4f33-914c-5e840d2f9612", + "parent": "dcd54745-3143-4b4d-b557-f9c8ce9c7e71", + "children": [ + "f4e68050-fdc7-48e6-b0e0-7c71aa7ff3df" + ], + "last_state_change": 1675380199.2281342, + "state": 4, + "task_spec": "Event_1q277cc", + "triggered": false, + "workflow_name": "parent", + "internal_data": {}, + "data": {} + }, + "f4e68050-fdc7-48e6-b0e0-7c71aa7ff3df": { + "id": "f4e68050-fdc7-48e6-b0e0-7c71aa7ff3df", + "parent": "3a537753-2578-4f33-914c-5e840d2f9612", + "children": [ + "04c50af7-cf65-4cd7-a25e-af506581de7c" + ], + "last_state_change": 1675380199.2283747, + "state": 4, + "task_spec": "parent.EndJoin", + "triggered": false, + "workflow_name": "parent", + "internal_data": {}, + "data": {} + }, + "04c50af7-cf65-4cd7-a25e-af506581de7c": { + "id": "04c50af7-cf65-4cd7-a25e-af506581de7c", + "parent": "f4e68050-fdc7-48e6-b0e0-7c71aa7ff3df", + "children": [], + "last_state_change": 1675380199.2286203, + "state": 4, + "task_spec": "End", + "triggered": false, + "workflow_name": "parent", + "internal_data": {}, + "data": {} + } + }, + "root": "4a2e2ad3-ad4b-4168-800d-71e31f33e225", + "spec": { + "name": "parent", + "description": "Parent Process", + "file": "/home/essweine/work/sartography/code/SpiffWorkflow/tests/SpiffWorkflow/bpmn/data/io_spec_parent_data_obj.bpmn", + "task_specs": { + "Start": { + "id": "parent_1", + "name": "Start", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [], + "outputs": [ + "Event_0xiw3t6" + ], + "typename": "StartTask" + }, + "parent.EndJoin": { + "id": "parent_2", + "name": "parent.EndJoin", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Event_1q277cc" + ], + "outputs": [ + "End" + ], + "typename": "_EndJoin" + }, + "End": { + "id": "parent_3", + "name": "End", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "parent.EndJoin" + ], + "outputs": [], + "typename": "Simple" + }, + "Event_0xiw3t6": { + "id": "parent_4", + "name": "Event_0xiw3t6", + "description": null, + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Start" + ], + "outputs": [ + "Activity_0haob58" + ], + "lane": null, + "documentation": null, + "loopTask": false, + "position": { + "x": 152.0, + "y": 102.0 + }, + "outgoing_sequence_flows": { + "Activity_0haob58": { + "id": "Flow_00qjfvu", + "name": null, + "documentation": null, + "target_task_spec": "Activity_0haob58", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Flow_00qjfvu": { + "id": "Flow_00qjfvu", + "name": null, + "documentation": null, + "target_task_spec": "Activity_0haob58", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "event_definition": { + "internal": false, + "external": false, + "typename": "NoneEventDefinition" + }, + "typename": "StartEvent", + "extensions": {} + }, + "Activity_0haob58": { + "id": "parent_5", + "name": "Activity_0haob58", + "description": "Set Data", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Event_0xiw3t6" + ], + "outputs": [ + "Activity_1wdjypm" + ], + "lane": null, + "documentation": null, + "loopTask": false, + "position": { + "x": 240.0, + "y": 80.0 + }, + "outgoing_sequence_flows": { + "Activity_1wdjypm": { + "id": "Flow_0aj70uj", + "name": null, + "documentation": null, + "target_task_spec": "Activity_1wdjypm", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Flow_0aj70uj": { + "id": "Flow_0aj70uj", + "name": null, + "documentation": null, + "target_task_spec": "Activity_1wdjypm", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [ + { + "name": "obj_1", + "description": "obj_1", + "typename": "BpmnDataSpecification" + } + ], + "script": "in_1, in_2, unused = 1, \"hello world\", True\nobj_1='object 1'", + "typename": "ScriptTask", + "extensions": {} + }, + "Activity_1wdjypm": { + "id": "parent_6", + "name": "Activity_1wdjypm", + "description": "Update Data", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Activity_0haob58" + ], + "outputs": [ + "Event_1q277cc" + ], + "lane": null, + "documentation": null, + "loopTask": false, + "position": { + "x": 400.0, + "y": 80.0 + }, + "outgoing_sequence_flows": { + "Event_1q277cc": { + "id": "Flow_1uel76w", + "name": null, + "documentation": null, + "target_task_spec": "Event_1q277cc", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Flow_1uel76w": { + "id": "Flow_1uel76w", + "name": null, + "documentation": null, + "target_task_spec": "Event_1q277cc", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "spec": "subprocess", + "typename": "CallActivity", + "extensions": {} + }, + "Event_1q277cc": { + "id": "parent_7", + "name": "Event_1q277cc", + "description": null, + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Activity_1wdjypm" + ], + "outputs": [ + "parent.EndJoin" + ], + "lane": null, + "documentation": null, + "loopTask": false, + "position": { + "x": 562.0, + "y": 102.0 + }, + "outgoing_sequence_flows": { + "parent.EndJoin": { + "id": "Event_1q277cc.ToEndJoin", + "name": null, + "documentation": null, + "target_task_spec": "parent.EndJoin", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Event_1q277cc.ToEndJoin": { + "id": "Event_1q277cc.ToEndJoin", + "name": null, + "documentation": null, + "target_task_spec": "parent.EndJoin", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "event_definition": { + "internal": false, + "external": false, + "typename": "NoneEventDefinition" + }, + "typename": "EndEvent", + "extensions": {} + }, + "Root": { + "id": "parent_8", + "name": "Root", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [], + "outputs": [], + "typename": "Simple" + } + }, + "data_inputs": [], + "data_outputs": [], + "data_objects": { + "obj_1": { + "name": "obj_1", + "description": "obj_1", + "typename": "BpmnDataSpecification" + } + }, + "correlation_keys": {}, + "typename": "BpmnProcessSpec" + }, + "subprocess_specs": { + "subprocess": { + "name": "subprocess", + "description": "subprocess", + "file": "/home/essweine/work/sartography/code/SpiffWorkflow/tests/SpiffWorkflow/bpmn/data/io_spec.bpmn", + "task_specs": { + "Start": { + "id": "subprocess_1", + "name": "Start", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [], + "outputs": [ + "Event_1rtivo5" + ], + "typename": "StartTask" + }, + "subprocess.EndJoin": { + "id": "subprocess_2", + "name": "subprocess.EndJoin", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Event_0pgucu1" + ], + "outputs": [ + "End" + ], + "typename": "_EndJoin" + }, + "End": { + "id": "subprocess_3", + "name": "End", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "subprocess.EndJoin" + ], + "outputs": [], + "typename": "Simple" + }, + "Event_1rtivo5": { + "id": "subprocess_4", + "name": "Event_1rtivo5", + "description": null, + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Start" + ], + "outputs": [ + "Activity_04d94ee" + ], + "lane": null, + "documentation": null, + "loopTask": false, + "position": { + "x": 232.0, + "y": 252.0 + }, + "outgoing_sequence_flows": { + "Activity_04d94ee": { + "id": "Flow_0n038fc", + "name": null, + "documentation": null, + "target_task_spec": "Activity_04d94ee", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Flow_0n038fc": { + "id": "Flow_0n038fc", + "name": null, + "documentation": null, + "target_task_spec": "Activity_04d94ee", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "event_definition": { + "internal": false, + "external": false, + "typename": "NoneEventDefinition" + }, + "typename": "StartEvent", + "extensions": {} + }, + "Activity_04d94ee": { + "id": "subprocess_5", + "name": "Activity_04d94ee", + "description": "Task 1", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Event_1rtivo5" + ], + "outputs": [ + "Event_0pgucu1" + ], + "lane": null, + "documentation": null, + "loopTask": false, + "position": { + "x": 320.0, + "y": 230.0 + }, + "outgoing_sequence_flows": { + "Event_0pgucu1": { + "id": "Flow_1d3l0mt", + "name": null, + "documentation": null, + "target_task_spec": "Event_0pgucu1", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Flow_1d3l0mt": { + "id": "Flow_1d3l0mt", + "name": null, + "documentation": null, + "target_task_spec": "Event_0pgucu1", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "script": "out_1, out_2, unused = in_1 * 2, in_2.upper(), False\n ", + "typename": "ScriptTask", + "extensions": {} + }, + "Event_0pgucu1": { + "id": "subprocess_6", + "name": "Event_0pgucu1", + "description": null, + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Activity_04d94ee" + ], + "outputs": [ + "subprocess.EndJoin" + ], + "lane": null, + "documentation": null, + "loopTask": false, + "position": { + "x": 472.0, + "y": 252.0 + }, + "outgoing_sequence_flows": { + "subprocess.EndJoin": { + "id": "Event_0pgucu1.ToEndJoin", + "name": null, + "documentation": null, + "target_task_spec": "subprocess.EndJoin", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Event_0pgucu1.ToEndJoin": { + "id": "Event_0pgucu1.ToEndJoin", + "name": null, + "documentation": null, + "target_task_spec": "subprocess.EndJoin", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "event_definition": { + "internal": false, + "external": false, + "typename": "NoneEventDefinition" + }, + "typename": "EndEvent", + "extensions": {} + }, + "Root": { + "id": "subprocess_7", + "name": "Root", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [], + "outputs": [], + "typename": "Simple" + } + }, + "data_inputs": [ + { + "name": "in_1", + "description": "input 1", + "typename": "BpmnDataSpecification" + }, + { + "name": "in_2", + "description": "input 2", + "typename": "BpmnDataSpecification" + } + ], + "data_outputs": [ + { + "name": "out_1", + "description": "output 1", + "typename": "BpmnDataSpecification" + }, + { + "name": "out_2", + "description": "output 2", + "typename": "BpmnDataSpecification" + } + ], + "data_objects": {}, + "correlation_keys": {}, + "typename": "BpmnProcessSpec" + } + }, + "subprocesses": { + "dcd54745-3143-4b4d-b557-f9c8ce9c7e71": { + "data": { + "obj_1": "object 1" + }, + "last_task": null, + "success": true, + "tasks": { + "658250f5-54df-4300-9e0a-6e122ed17e08": { + "id": "658250f5-54df-4300-9e0a-6e122ed17e08", + "parent": null, + "children": [ + "cce657f0-4534-4923-b073-0213caf8d500" + ], + "last_state_change": 1675380199.240486, + "state": 32, + "task_spec": "Root", + "triggered": false, + "workflow_name": "Activity_1wdjypm", + "internal_data": {}, + "data": {} + }, + "cce657f0-4534-4923-b073-0213caf8d500": { + "id": "cce657f0-4534-4923-b073-0213caf8d500", + "parent": "658250f5-54df-4300-9e0a-6e122ed17e08", + "children": [ + "d0fd83e5-e4fb-49fb-9055-27993fa09430" + ], + "last_state_change": 1675380199.24384, + "state": 16, + "task_spec": "Start", + "triggered": false, + "workflow_name": "Activity_1wdjypm", + "internal_data": {}, + "data": { + "in_1": 1, + "in_2": "hello world" + } + }, + "d0fd83e5-e4fb-49fb-9055-27993fa09430": { + "id": "d0fd83e5-e4fb-49fb-9055-27993fa09430", + "parent": "cce657f0-4534-4923-b073-0213caf8d500", + "children": [ + "48649a1e-9fe5-48ef-8bd9-57b60ff4e98b" + ], + "last_state_change": 1675380199.2407098, + "state": 4, + "task_spec": "Event_1rtivo5", + "triggered": false, + "workflow_name": "Activity_1wdjypm", + "internal_data": {}, + "data": {} + }, + "48649a1e-9fe5-48ef-8bd9-57b60ff4e98b": { + "id": "48649a1e-9fe5-48ef-8bd9-57b60ff4e98b", + "parent": "d0fd83e5-e4fb-49fb-9055-27993fa09430", + "children": [ + "984b7e3e-b037-4120-a544-792d5ee91fe5" + ], + "last_state_change": 1675380199.240903, + "state": 4, + "task_spec": "Activity_04d94ee", + "triggered": false, + "workflow_name": "Activity_1wdjypm", + "internal_data": {}, + "data": {} + }, + "984b7e3e-b037-4120-a544-792d5ee91fe5": { + "id": "984b7e3e-b037-4120-a544-792d5ee91fe5", + "parent": "48649a1e-9fe5-48ef-8bd9-57b60ff4e98b", + "children": [ + "8b4d7999-b35b-480f-8e3d-08ad24883bce" + ], + "last_state_change": 1675380199.2411075, + "state": 4, + "task_spec": "Event_0pgucu1", + "triggered": false, + "workflow_name": "Activity_1wdjypm", + "internal_data": {}, + "data": {} + }, + "8b4d7999-b35b-480f-8e3d-08ad24883bce": { + "id": "8b4d7999-b35b-480f-8e3d-08ad24883bce", + "parent": "984b7e3e-b037-4120-a544-792d5ee91fe5", + "children": [ + "0ad22900-dac5-4ce8-8fcf-644849cf8827" + ], + "last_state_change": 1675380199.2413251, + "state": 4, + "task_spec": "subprocess.EndJoin", + "triggered": false, + "workflow_name": "Activity_1wdjypm", + "internal_data": {}, + "data": {} + }, + "0ad22900-dac5-4ce8-8fcf-644849cf8827": { + "id": "0ad22900-dac5-4ce8-8fcf-644849cf8827", + "parent": "8b4d7999-b35b-480f-8e3d-08ad24883bce", + "children": [], + "last_state_change": 1675380199.2415493, + "state": 4, + "task_spec": "End", + "triggered": false, + "workflow_name": "Activity_1wdjypm", + "internal_data": {}, + "data": {} + } + }, + "root": "658250f5-54df-4300-9e0a-6e122ed17e08" + } + }, + "bpmn_messages": [] +} diff --git a/tests/SpiffWorkflow/bpmn/data/serialization/v1.1-gateways.json b/tests/SpiffWorkflow/bpmn/data/serialization/v1.1-gateways.json new file mode 100644 index 000000000..b79872556 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/serialization/v1.1-gateways.json @@ -0,0 +1,830 @@ +{ + "serializer_version": "1.1", + "data": {}, + "last_task": "215867bf-41a3-42b3-8403-b836aabcfe6c", + "success": true, + "tasks": { + "01bdb086-35cc-4897-805f-d059d1cfe682": { + "id": "01bdb086-35cc-4897-805f-d059d1cfe682", + "parent": null, + "children": [ + "3846b631-5ed5-4913-9f53-f358886547cd" + ], + "last_state_change": 1675380654.3327675, + "state": 32, + "task_spec": "Root", + "triggered": false, + "workflow_name": "lanes", + "internal_data": {}, + "data": {} + }, + "3846b631-5ed5-4913-9f53-f358886547cd": { + "id": "3846b631-5ed5-4913-9f53-f358886547cd", + "parent": "01bdb086-35cc-4897-805f-d059d1cfe682", + "children": [ + "7f261ef4-047b-4941-a508-c24790f0a8c0" + ], + "last_state_change": 1675380654.338419, + "state": 32, + "task_spec": "Start", + "triggered": false, + "workflow_name": "lanes", + "internal_data": {}, + "data": {} + }, + "7f261ef4-047b-4941-a508-c24790f0a8c0": { + "id": "7f261ef4-047b-4941-a508-c24790f0a8c0", + "parent": "3846b631-5ed5-4913-9f53-f358886547cd", + "children": [ + "215867bf-41a3-42b3-8403-b836aabcfe6c" + ], + "last_state_change": 1675380654.3411734, + "state": 32, + "task_spec": "StartEvent_1", + "triggered": false, + "workflow_name": "lanes", + "internal_data": { + "event_fired": true + }, + "data": {} + }, + "215867bf-41a3-42b3-8403-b836aabcfe6c": { + "id": "215867bf-41a3-42b3-8403-b836aabcfe6c", + "parent": "7f261ef4-047b-4941-a508-c24790f0a8c0", + "children": [ + "5b0dc44b-0901-4989-8733-2dfcb82344c7" + ], + "last_state_change": 1675380654.3452208, + "state": 32, + "task_spec": "Activity_A1", + "triggered": false, + "workflow_name": "lanes", + "internal_data": {}, + "data": {} + }, + "5b0dc44b-0901-4989-8733-2dfcb82344c7": { + "id": "5b0dc44b-0901-4989-8733-2dfcb82344c7", + "parent": "215867bf-41a3-42b3-8403-b836aabcfe6c", + "children": [ + "bf645868-c2fc-4dfb-90c9-210f23b7f503" + ], + "last_state_change": 1675380654.3462226, + "state": 16, + "task_spec": "Activity_B1", + "triggered": false, + "workflow_name": "lanes", + "internal_data": {}, + "data": {} + }, + "bf645868-c2fc-4dfb-90c9-210f23b7f503": { + "id": "bf645868-c2fc-4dfb-90c9-210f23b7f503", + "parent": "5b0dc44b-0901-4989-8733-2dfcb82344c7", + "children": [ + "3825a6af-4ea6-4242-9570-411a7d080f96", + "90b2d2bc-d222-4c96-95e5-9becd7260ef6" + ], + "last_state_change": 1675380654.3340564, + "state": 4, + "task_spec": "Gateway_askQuestion", + "triggered": false, + "workflow_name": "lanes", + "internal_data": {}, + "data": {} + }, + "3825a6af-4ea6-4242-9570-411a7d080f96": { + "id": "3825a6af-4ea6-4242-9570-411a7d080f96", + "parent": "bf645868-c2fc-4dfb-90c9-210f23b7f503", + "children": [ + "a00fc3d7-c0ab-46ec-a3b1-892ff78f4809" + ], + "last_state_change": 1675380654.3344204, + "state": 1, + "task_spec": "Activity_A2", + "triggered": false, + "workflow_name": "lanes", + "internal_data": {}, + "data": {} + }, + "a00fc3d7-c0ab-46ec-a3b1-892ff78f4809": { + "id": "a00fc3d7-c0ab-46ec-a3b1-892ff78f4809", + "parent": "3825a6af-4ea6-4242-9570-411a7d080f96", + "children": [], + "last_state_change": 1675380654.3349297, + "state": 1, + "task_spec": "Implement_Feature", + "triggered": false, + "workflow_name": "lanes", + "internal_data": {}, + "data": {} + }, + "90b2d2bc-d222-4c96-95e5-9becd7260ef6": { + "id": "90b2d2bc-d222-4c96-95e5-9becd7260ef6", + "parent": "bf645868-c2fc-4dfb-90c9-210f23b7f503", + "children": [ + "3eeb1f48-6bde-4921-b2b0-ae4557c09d1f" + ], + "last_state_change": 1675380654.3346882, + "state": 2, + "task_spec": "Implement_Feature", + "triggered": false, + "workflow_name": "lanes", + "internal_data": {}, + "data": {} + }, + "3eeb1f48-6bde-4921-b2b0-ae4557c09d1f": { + "id": "3eeb1f48-6bde-4921-b2b0-ae4557c09d1f", + "parent": "90b2d2bc-d222-4c96-95e5-9becd7260ef6", + "children": [], + "last_state_change": 1675380654.3352633, + "state": 2, + "task_spec": "Activity_1uksrqx", + "triggered": false, + "workflow_name": "lanes", + "internal_data": {}, + "data": {} + } + }, + "root": "01bdb086-35cc-4897-805f-d059d1cfe682", + "spec": { + "name": "lanes", + "description": "lanes", + "file": "/home/essweine/work/sartography/code/SpiffWorkflow/tests/SpiffWorkflow/bpmn/data/lanes.bpmn", + "task_specs": { + "Start": { + "id": "lanes_1", + "name": "Start", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [], + "outputs": [ + "StartEvent_1" + ], + "typename": "StartTask" + }, + "lanes.EndJoin": { + "id": "lanes_2", + "name": "lanes.EndJoin", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Event_07pakcl" + ], + "outputs": [ + "End" + ], + "typename": "_EndJoin" + }, + "End": { + "id": "lanes_3", + "name": "End", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "lanes.EndJoin" + ], + "outputs": [], + "typename": "Simple" + }, + "StartEvent_1": { + "id": "lanes_4", + "name": "StartEvent_1", + "description": null, + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Start" + ], + "outputs": [ + "Activity_A1" + ], + "lane": "A", + "documentation": null, + "loopTask": false, + "position": { + "x": 219.0, + "y": 92.0 + }, + "outgoing_sequence_flows": { + "Activity_A1": { + "id": "Flow_0jwejm5", + "name": null, + "documentation": null, + "target_task_spec": "Activity_A1", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Flow_0jwejm5": { + "id": "Flow_0jwejm5", + "name": null, + "documentation": null, + "target_task_spec": "Activity_A1", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "event_definition": { + "internal": false, + "external": false, + "typename": "NoneEventDefinition" + }, + "typename": "StartEvent", + "extensions": {} + }, + "Activity_A1": { + "id": "lanes_5", + "name": "Activity_A1", + "description": "Request Feature", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "StartEvent_1" + ], + "outputs": [ + "Activity_B1" + ], + "lane": "A", + "documentation": null, + "loopTask": false, + "position": { + "x": 300.0, + "y": 70.0 + }, + "outgoing_sequence_flows": { + "Activity_B1": { + "id": "Flow_140vffb", + "name": null, + "documentation": null, + "target_task_spec": "Activity_B1", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Flow_140vffb": { + "id": "Flow_140vffb", + "name": null, + "documentation": null, + "target_task_spec": "Activity_B1", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "typename": "UserTask", + "extensions": {} + }, + "Activity_B1": { + "id": "lanes_6", + "name": "Activity_B1", + "description": "Clarifying Questions?", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Activity_A1" + ], + "outputs": [ + "Gateway_askQuestion" + ], + "lane": "B", + "documentation": null, + "loopTask": false, + "position": { + "x": 300.0, + "y": 210.0 + }, + "outgoing_sequence_flows": { + "Gateway_askQuestion": { + "id": "Flow_1k9gsm1", + "name": null, + "documentation": null, + "target_task_spec": "Gateway_askQuestion", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Flow_1k9gsm1": { + "id": "Flow_1k9gsm1", + "name": null, + "documentation": null, + "target_task_spec": "Gateway_askQuestion", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "typename": "UserTask", + "extensions": {} + }, + "Gateway_askQuestion": { + "id": "lanes_7", + "name": "Gateway_askQuestion", + "description": "Do we need Clarifcation?", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Activity_B1" + ], + "outputs": [ + "Activity_A2", + "Implement_Feature" + ], + "lane": "B", + "documentation": null, + "loopTask": false, + "position": { + "x": 465.0, + "y": 225.0 + }, + "outgoing_sequence_flows": { + "Activity_A2": { + "id": "Flow_0okhwy0", + "name": "Yes", + "documentation": null, + "target_task_spec": "Activity_A2", + "typename": "SequenceFlow" + }, + "Implement_Feature": { + "id": "Flow_182bqvo", + "name": "No", + "documentation": null, + "target_task_spec": "Implement_Feature", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Flow_0okhwy0": { + "id": "Flow_0okhwy0", + "name": "Yes", + "documentation": null, + "target_task_spec": "Activity_A2", + "typename": "SequenceFlow" + }, + "Flow_182bqvo": { + "id": "Flow_182bqvo", + "name": "No", + "documentation": null, + "target_task_spec": "Implement_Feature", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "default_task_spec": "Implement_Feature", + "cond_task_specs": [ + { + "condition": "NeedClarification == 'Yes'", + "task_spec": "Activity_A2" + } + ], + "choice": null, + "typename": "ExclusiveGateway", + "extensions": {} + }, + "Implement_Feature": { + "id": "lanes_8", + "name": "Implement_Feature", + "description": "Implement Feature", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Activity_A2", + "Gateway_askQuestion" + ], + "outputs": [ + "Activity_1uksrqx" + ], + "lane": "B", + "documentation": null, + "loopTask": false, + "position": { + "x": 620.0, + "y": 200.0 + }, + "outgoing_sequence_flows": { + "Activity_1uksrqx": { + "id": "Flow_0xz2oco", + "name": null, + "documentation": null, + "target_task_spec": "Activity_1uksrqx", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Flow_0xz2oco": { + "id": "Flow_0xz2oco", + "name": null, + "documentation": null, + "target_task_spec": "Activity_1uksrqx", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "typename": "ManualTask", + "extensions": {} + }, + "Activity_1uksrqx": { + "id": "lanes_9", + "name": "Activity_1uksrqx", + "description": "Send to testing", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Implement_Feature" + ], + "outputs": [ + "Activity_0i0rxuw" + ], + "lane": "C", + "documentation": null, + "loopTask": false, + "position": { + "x": 620.0, + "y": 340.0 + }, + "outgoing_sequence_flows": { + "Activity_0i0rxuw": { + "id": "Flow_1cybznq", + "name": null, + "documentation": null, + "target_task_spec": "Activity_0i0rxuw", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Flow_1cybznq": { + "id": "Flow_1cybznq", + "name": null, + "documentation": null, + "target_task_spec": "Activity_0i0rxuw", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "typename": "ManualTask", + "extensions": {} + }, + "Activity_0i0rxuw": { + "id": "lanes_10", + "name": "Activity_0i0rxuw", + "description": null, + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Activity_1uksrqx" + ], + "outputs": [ + "Event_07pakcl" + ], + "lane": "C", + "documentation": null, + "loopTask": false, + "position": { + "x": 760.0, + "y": 320.0 + }, + "outgoing_sequence_flows": { + "Event_07pakcl": { + "id": "Flow_0e1uyol", + "name": null, + "documentation": null, + "target_task_spec": "Event_07pakcl", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Flow_0e1uyol": { + "id": "Flow_0e1uyol", + "name": null, + "documentation": null, + "target_task_spec": "Event_07pakcl", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "spec": "Activity_0i0rxuw", + "typename": "CallActivity", + "extensions": {} + }, + "Event_07pakcl": { + "id": "lanes_11", + "name": "Event_07pakcl", + "description": null, + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Activity_0i0rxuw" + ], + "outputs": [ + "lanes.EndJoin" + ], + "lane": "C", + "documentation": null, + "loopTask": false, + "position": { + "x": 1092.0, + "y": 362.0 + }, + "outgoing_sequence_flows": { + "lanes.EndJoin": { + "id": "Event_07pakcl.ToEndJoin", + "name": null, + "documentation": null, + "target_task_spec": "lanes.EndJoin", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Event_07pakcl.ToEndJoin": { + "id": "Event_07pakcl.ToEndJoin", + "name": null, + "documentation": null, + "target_task_spec": "lanes.EndJoin", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "event_definition": { + "internal": false, + "external": false, + "typename": "NoneEventDefinition" + }, + "typename": "EndEvent", + "extensions": {} + }, + "Activity_A2": { + "id": "lanes_12", + "name": "Activity_A2", + "description": "Clarify Request", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Gateway_askQuestion" + ], + "outputs": [ + "Implement_Feature" + ], + "lane": "A", + "documentation": null, + "loopTask": false, + "position": { + "x": 530.0, + "y": 70.0 + }, + "outgoing_sequence_flows": { + "Implement_Feature": { + "id": "Flow_17rng3c", + "name": null, + "documentation": null, + "target_task_spec": "Implement_Feature", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Flow_17rng3c": { + "id": "Flow_17rng3c", + "name": null, + "documentation": null, + "target_task_spec": "Implement_Feature", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "typename": "UserTask", + "extensions": {} + }, + "Root": { + "id": "lanes_13", + "name": "Root", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [], + "outputs": [], + "typename": "Simple" + } + }, + "data_inputs": [], + "data_outputs": [], + "data_objects": {}, + "correlation_keys": {}, + "typename": "BpmnProcessSpec" + }, + "subprocess_specs": { + "Activity_0i0rxuw": { + "name": "Activity_0i0rxuw", + "description": "Activity_0i0rxuw", + "file": "/home/essweine/work/sartography/code/SpiffWorkflow/tests/SpiffWorkflow/bpmn/data/lanes.bpmn", + "task_specs": { + "Start": { + "id": "Activity_0i0rxuw_1", + "name": "Start", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [], + "outputs": [ + "Event_0lbloj7" + ], + "typename": "StartTask" + }, + "Activity_0i0rxuw.EndJoin": { + "id": "Activity_0i0rxuw_2", + "name": "Activity_0i0rxuw.EndJoin", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Event_1vz21ww" + ], + "outputs": [ + "End" + ], + "typename": "_EndJoin" + }, + "End": { + "id": "Activity_0i0rxuw_3", + "name": "End", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Activity_0i0rxuw.EndJoin" + ], + "outputs": [], + "typename": "Simple" + }, + "Event_0lbloj7": { + "id": "Activity_0i0rxuw_4", + "name": "Event_0lbloj7", + "description": null, + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Start" + ], + "outputs": [ + "SubProcessTask" + ], + "lane": "C", + "documentation": null, + "loopTask": false, + "position": { + "x": 782.0, + "y": 362.0 + }, + "outgoing_sequence_flows": { + "SubProcessTask": { + "id": "Flow_086ghyu", + "name": null, + "documentation": null, + "target_task_spec": "SubProcessTask", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Flow_086ghyu": { + "id": "Flow_086ghyu", + "name": null, + "documentation": null, + "target_task_spec": "SubProcessTask", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "event_definition": { + "internal": false, + "external": false, + "typename": "NoneEventDefinition" + }, + "typename": "StartEvent", + "extensions": {} + }, + "SubProcessTask": { + "id": "Activity_0i0rxuw_5", + "name": "SubProcessTask", + "description": "SubProcessTask", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Event_0lbloj7" + ], + "outputs": [ + "Event_1vz21ww" + ], + "lane": "C", + "documentation": null, + "loopTask": false, + "position": { + "x": 850.0, + "y": 340.0 + }, + "outgoing_sequence_flows": { + "Event_1vz21ww": { + "id": "Flow_1jw6qrj", + "name": null, + "documentation": null, + "target_task_spec": "Event_1vz21ww", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Flow_1jw6qrj": { + "id": "Flow_1jw6qrj", + "name": null, + "documentation": null, + "target_task_spec": "Event_1vz21ww", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "typename": "ManualTask", + "extensions": {} + }, + "Event_1vz21ww": { + "id": "Activity_0i0rxuw_6", + "name": "Event_1vz21ww", + "description": null, + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "SubProcessTask" + ], + "outputs": [ + "Activity_0i0rxuw.EndJoin" + ], + "lane": "C", + "documentation": null, + "loopTask": false, + "position": { + "x": 982.0, + "y": 362.0 + }, + "outgoing_sequence_flows": { + "Activity_0i0rxuw.EndJoin": { + "id": "Event_1vz21ww.ToEndJoin", + "name": null, + "documentation": null, + "target_task_spec": "Activity_0i0rxuw.EndJoin", + "typename": "SequenceFlow" + } + }, + "outgoing_sequence_flows_by_id": { + "Event_1vz21ww.ToEndJoin": { + "id": "Event_1vz21ww.ToEndJoin", + "name": null, + "documentation": null, + "target_task_spec": "Activity_0i0rxuw.EndJoin", + "typename": "SequenceFlow" + } + }, + "data_input_associations": [], + "data_output_associations": [], + "event_definition": { + "internal": false, + "external": false, + "typename": "NoneEventDefinition" + }, + "typename": "EndEvent", + "extensions": {} + } + }, + "data_inputs": [], + "data_outputs": [], + "data_objects": {}, + "correlation_keys": {}, + "typename": "BpmnProcessSpec" + } + }, + "subprocesses": {}, + "bpmn_messages": [] +} diff --git a/tests/SpiffWorkflow/bpmn/data/serialization/v1.1-multi.json b/tests/SpiffWorkflow/bpmn/data/serialization/v1.1-multi.json new file mode 100644 index 000000000..122d5a21f --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/serialization/v1.1-multi.json @@ -0,0 +1,350 @@ +{ + "serializer_version": "1.1", + "data": {}, + "last_task": "ca089728-9745-4d50-8fbc-f2f7234dec8f", + "success": true, + "tasks": { + "fa4b8656-22a2-467e-8fb0-9b1d8f1f6da6": { + "id": "fa4b8656-22a2-467e-8fb0-9b1d8f1f6da6", + "parent": null, + "children": [ + "ccf50f31-880b-406a-9e61-2f3d42f39d70" + ], + "last_state_change": 1676389310.7311432, + "state": 32, + "task_spec": "Root", + "triggered": false, + "workflow_name": "main", + "internal_data": {}, + "data": {} + }, + "ccf50f31-880b-406a-9e61-2f3d42f39d70": { + "id": "ccf50f31-880b-406a-9e61-2f3d42f39d70", + "parent": "fa4b8656-22a2-467e-8fb0-9b1d8f1f6da6", + "children": [ + "ca089728-9745-4d50-8fbc-f2f7234dec8f" + ], + "last_state_change": 1676389310.735502, + "state": 32, + "task_spec": "Start", + "triggered": false, + "workflow_name": "main", + "internal_data": {}, + "data": { + "input_data": [ + 1, + 2, + 3 + ] + } + }, + "ca089728-9745-4d50-8fbc-f2f7234dec8f": { + "id": "ca089728-9745-4d50-8fbc-f2f7234dec8f", + "parent": "ccf50f31-880b-406a-9e61-2f3d42f39d70", + "children": [ + "513dba6b-7017-48df-a1e0-7a2c57a1042c" + ], + "last_state_change": 1676389310.739117, + "state": 32, + "task_spec": "StartEvent_1", + "triggered": false, + "workflow_name": "main", + "internal_data": { + "event_fired": true + }, + "data": { + "input_data": [ + 1, + 2, + 3 + ] + } + }, + "513dba6b-7017-48df-a1e0-7a2c57a1042c": { + "id": "513dba6b-7017-48df-a1e0-7a2c57a1042c", + "parent": "ca089728-9745-4d50-8fbc-f2f7234dec8f", + "children": [ + "638ea876-beb2-4fd6-9dc3-5fd528d7cfb9" + ], + "last_state_change": 1676389310.7412922, + "state": 16, + "task_spec": "Gateway_for_any_task_start", + "triggered": false, + "workflow_name": "main", + "internal_data": {}, + "data": { + "input_data": [ + 1, + 2, + 3 + ] + } + }, + "638ea876-beb2-4fd6-9dc3-5fd528d7cfb9": { + "id": "638ea876-beb2-4fd6-9dc3-5fd528d7cfb9", + "parent": "513dba6b-7017-48df-a1e0-7a2c57a1042c", + "children": [ + "ec145fea-d068-4401-9f6c-6903cf153b23" + ], + "last_state_change": 1676389310.7315657, + "state": 4, + "task_spec": "any_task", + "triggered": false, + "workflow_name": "main", + "internal_data": { + "splits": 1, + "runtimes": 1 + }, + "data": { + "item": 1 + } + }, + "ec145fea-d068-4401-9f6c-6903cf153b23": { + "id": "ec145fea-d068-4401-9f6c-6903cf153b23", + "parent": "638ea876-beb2-4fd6-9dc3-5fd528d7cfb9", + "children": [ + "eccb7e2f-4b23-4b75-b9fb-e3b3a335574f" + ], + "last_state_change": 1676389310.7325432, + "state": 1, + "task_spec": "Gateway_for_any_task_end", + "triggered": false, + "workflow_name": "main", + "internal_data": {}, + "data": {} + }, + "eccb7e2f-4b23-4b75-b9fb-e3b3a335574f": { + "id": "eccb7e2f-4b23-4b75-b9fb-e3b3a335574f", + "parent": "ec145fea-d068-4401-9f6c-6903cf153b23", + "children": [], + "last_state_change": 1676389310.732967, + "state": 1, + "task_spec": "Event_0a6d9t5", + "triggered": false, + "workflow_name": "main", + "internal_data": {}, + "data": {} + } + }, + "root": "fa4b8656-22a2-467e-8fb0-9b1d8f1f6da6", + "spec": { + "name": "main", + "description": "main", + "file": "/home/essweine/work/sartography/code/SpiffWorkflow/tests/SpiffWorkflow/bpmn/data/diagram_1.bpmn", + "task_specs": { + "Start": { + "id": "main_1", + "name": "Start", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [], + "outputs": [ + "StartEvent_1" + ], + "typename": "StartTask" + }, + "main.EndJoin": { + "id": "main_2", + "name": "main.EndJoin", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Event_0a6d9t5" + ], + "outputs": [ + "End" + ], + "typename": "_EndJoin" + }, + "End": { + "id": "main_3", + "name": "End", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "main.EndJoin" + ], + "outputs": [], + "typename": "Simple" + }, + "StartEvent_1": { + "id": "main_4", + "name": "StartEvent_1", + "description": null, + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Start" + ], + "outputs": [ + "Gateway_for_any_task_start" + ], + "lane": null, + "documentation": null, + "loopTask": false, + "position": { + "x": 179.0, + "y": 99.0 + }, + "data_input_associations": [], + "data_output_associations": [], + "event_definition": { + "internal": false, + "external": false, + "typename": "NoneEventDefinition" + }, + "typename": "StartEvent", + "extensions": {} + }, + "any_task": { + "id": "main_5", + "name": "any_task", + "description": "Any Task", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "StartEvent_1", + "Gateway_for_any_task_start" + ], + "outputs": [ + "Gateway_for_any_task_end" + ], + "lane": null, + "documentation": null, + "loopTask": false, + "position": { + "x": 270.0, + "y": 77.0 + }, + "data_input_associations": [], + "data_output_associations": [], + "typename": "NoneTask", + "times": { + "name": "input_data", + "typename": "Attrib" + }, + "elementVar": "item", + "collection": { + "name": "output_data", + "typename": "Attrib" + }, + "completioncondition": null, + "prevtaskclass": "SpiffWorkflow.bpmn.specs.NoneTask.NoneTask", + "isSequential": false, + "expanded": 1, + "extensions": {} + }, + "Event_0a6d9t5": { + "id": "main_6", + "name": "Event_0a6d9t5", + "description": null, + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "any_task" + ], + "outputs": [ + "main.EndJoin" + ], + "lane": null, + "documentation": null, + "loopTask": false, + "position": { + "x": 432.0, + "y": 99.0 + }, + "data_input_associations": [], + "data_output_associations": [], + "event_definition": { + "internal": false, + "external": false, + "typename": "NoneEventDefinition" + }, + "typename": "EndEvent", + "extensions": {} + }, + "Root": { + "id": "main_7", + "name": "Root", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [], + "outputs": [], + "typename": "Simple" + }, + "Gateway_for_any_task_start": { + "id": "main_8", + "name": "Gateway_for_any_task_start", + "description": "Begin Gateway", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "StartEvent_1" + ], + "outputs": [ + "any_task" + ], + "lane": null, + "documentation": null, + "loopTask": false, + "position": { + "x": 0, + "y": 0 + }, + "data_input_associations": [], + "data_output_associations": [], + "split_task": null, + "threshold": null, + "cancel": false, + "typename": "ParallelGateway" + }, + "Gateway_for_any_task_end": { + "id": "main_9", + "name": "Gateway_for_any_task_end", + "description": "End Gateway", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "any_task" + ], + "outputs": [ + "Event_0a6d9t5" + ], + "lane": null, + "documentation": null, + "loopTask": false, + "position": { + "x": 0, + "y": 0 + }, + "data_input_associations": [], + "data_output_associations": [], + "split_task": null, + "threshold": null, + "cancel": false, + "typename": "ParallelGateway" + } + }, + "data_inputs": [], + "data_outputs": [], + "data_objects": {}, + "correlation_keys": {}, + "typename": "BpmnProcessSpec" + }, + "subprocess_specs": {}, + "subprocesses": {}, + "bpmn_messages": [] +} diff --git a/tests/SpiffWorkflow/bpmn/data/serialization/v1-1.json b/tests/SpiffWorkflow/bpmn/data/serialization/v1.1-timers.json similarity index 100% rename from tests/SpiffWorkflow/bpmn/data/serialization/v1-1.json rename to tests/SpiffWorkflow/bpmn/data/serialization/v1.1-timers.json diff --git a/tests/SpiffWorkflow/bpmn/data/standard_loop.bpmn b/tests/SpiffWorkflow/bpmn/data/standard_loop.bpmn new file mode 100644 index 000000000..1e08e3e27 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/standard_loop.bpmn @@ -0,0 +1,41 @@ + + + + + Flow_0m77cxj + + + Flow_0m77cxj + Flow_1jbp2el + + done + + + + + Flow_1jbp2el + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/bpmn/data/standard_loop_invalid.bpmn b/tests/SpiffWorkflow/bpmn/data/standard_loop_invalid.bpmn new file mode 100644 index 000000000..3696e100e --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/standard_loop_invalid.bpmn @@ -0,0 +1,39 @@ + + + + + Flow_0m77cxj + + + Flow_0m77cxj + Flow_1jbp2el + + + + + Flow_1jbp2el + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/bpmn/data/sub_within_sub_multi.bpmn b/tests/SpiffWorkflow/bpmn/data/sub_within_sub_multi.bpmn deleted file mode 100644 index 95e29da0d..000000000 --- a/tests/SpiffWorkflow/bpmn/data/sub_within_sub_multi.bpmn +++ /dev/null @@ -1,129 +0,0 @@ - - - - - Flow_0dsbqk4 - - - - Flow_18e9qgr - - - Flow_1ona7kk - Flow_18e9qgr - - - Flow_05tjul5 - - - Flow_1pc1vib - - - Flow_1pc1vib - Flow_05tjul5 - - Flow_0hikak1 - - - Flow_0hikak1 - Flow_0oby5rd - my_var['new_info'] = "Adding this!" -my_var['name'] = my_var['name'] + "_edit" - - - - - Flow_0oby5rd - - - - - - - - - - Flow_0dsbqk4 - Flow_1ona7kk - my_collection = { - 'a':{'name':'Apple'}, - 'b':{'name':'Bubble'}, - 'c':{'name':'Crap, I should write better code'} -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/bpmn/data/sub_workflow_multi.bpmn b/tests/SpiffWorkflow/bpmn/data/sub_workflow_multi.bpmn deleted file mode 100644 index 1fb69933c..000000000 --- a/tests/SpiffWorkflow/bpmn/data/sub_workflow_multi.bpmn +++ /dev/null @@ -1,93 +0,0 @@ - - - - - Flow_0dsbqk4 - - - - Flow_18e9qgr - - - Flow_1ona7kk - Flow_18e9qgr - - - Flow_14l2ton - Flow_06gypww - my_var['new_info'] = "Adding this!" -my_var['name'] = my_var['name'] + "_edit" - - - Flow_06gypww - - - Flow_14l2ton - - - - - - - - Flow_0dsbqk4 - Flow_1ona7kk - my_collection = { - 'a':{'name':'Apple'}, - 'b':{'name':'Bubble'}, - 'c':{'name':'Crap, I should write better code'} -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/bpmn/data/sub_workflow_multi1.bpmn b/tests/SpiffWorkflow/bpmn/data/sub_workflow_multi1.bpmn deleted file mode 100644 index 478e18ffa..000000000 --- a/tests/SpiffWorkflow/bpmn/data/sub_workflow_multi1.bpmn +++ /dev/null @@ -1,59 +0,0 @@ - - - - - Flow_0dsbqk4 - - - - Flow_1lbqsop - - - Flow_0n1o8w6 - Flow_1lbqsop - - 5 - done==True - - x = {'a':a} -if a==3: - done=True -a=x - - - - - Flow_0dsbqk4 - Flow_0n1o8w6 - done=False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/bpmn/data/sub_workflow_multi_parallel.bpmn b/tests/SpiffWorkflow/bpmn/data/sub_workflow_multi_parallel.bpmn deleted file mode 100644 index b89d98f66..000000000 --- a/tests/SpiffWorkflow/bpmn/data/sub_workflow_multi_parallel.bpmn +++ /dev/null @@ -1,93 +0,0 @@ - - - - - Flow_0dsbqk4 - - - - Flow_18e9qgr - - - Flow_1ona7kk - Flow_18e9qgr - - - Flow_14l2ton - Flow_06gypww - my_var['new_info'] = "Adding this!" -my_var['name'] = my_var['name'] + "_edit" - - - Flow_06gypww - - - Flow_14l2ton - - - - - - - - Flow_0dsbqk4 - Flow_1ona7kk - my_collection = { - 'a':{'name':'Apple'}, - 'b':{'name':'Bubble'}, - 'c':{'name':'Crap, I should write better code'} -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/bpmn/data/two_top_level_procs.bpmn b/tests/SpiffWorkflow/bpmn/data/two_top_level_procs.bpmn deleted file mode 100644 index 363ccc120..000000000 --- a/tests/SpiffWorkflow/bpmn/data/two_top_level_procs.bpmn +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - Flow_1fumg40 - - - - Flow_1sfcxwo - - - - Flow_1fumg40 - Flow_1sfcxwo - - - - - Flow_0ptjvq1 - - - - Flow_12xe6lg - - - - Flow_0ptjvq1 - Flow_12xe6lg - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/bpmn/events/EventBasedGatewayTest.py b/tests/SpiffWorkflow/bpmn/events/EventBasedGatewayTest.py index 29febd248..529852ee2 100644 --- a/tests/SpiffWorkflow/bpmn/events/EventBasedGatewayTest.py +++ b/tests/SpiffWorkflow/bpmn/events/EventBasedGatewayTest.py @@ -8,7 +8,7 @@ from SpiffWorkflow.task import TaskState from ..BpmnWorkflowTestCase import BpmnWorkflowTestCase -class EventBsedGatewayTest(BpmnWorkflowTestCase): +class EventBasedGatewayTest(BpmnWorkflowTestCase): def setUp(self): self.spec, self.subprocesses = self.load_workflow_spec('event-gateway.bpmn', 'Process_0pvx19v') diff --git a/tests/SpiffWorkflow/bpmn/events/TransactionSubprocssTest.py b/tests/SpiffWorkflow/bpmn/events/TransactionSubprocssTest.py index 1212d776c..02a8389fb 100644 --- a/tests/SpiffWorkflow/bpmn/events/TransactionSubprocssTest.py +++ b/tests/SpiffWorkflow/bpmn/events/TransactionSubprocssTest.py @@ -29,17 +29,17 @@ class TransactionSubprocessTest(BpmnWorkflowTestCase): # Check that workflow and next task completed subprocess = self.workflow.get_tasks_from_spec_name('Subprocess')[0] - self.assertEqual(subprocess.get_state(), TaskState.COMPLETED) + self.assertEqual(subprocess.state, TaskState.COMPLETED) print_task = self.workflow.get_tasks_from_spec_name("Activity_Print_Data")[0] - self.assertEqual(print_task.get_state(), TaskState.COMPLETED) + self.assertEqual(print_task.state, TaskState.COMPLETED) # Check that the boundary events were cancelled cancel_task = self.workflow.get_tasks_from_spec_name("Catch_Cancel_Event")[0] - self.assertEqual(cancel_task.get_state(), TaskState.CANCELLED) + self.assertEqual(cancel_task.state, TaskState.CANCELLED) error_1_task = self.workflow.get_tasks_from_spec_name("Catch_Error_1")[0] - self.assertEqual(error_1_task.get_state(), TaskState.CANCELLED) + self.assertEqual(error_1_task.state, TaskState.CANCELLED) error_none_task = self.workflow.get_tasks_from_spec_name("Catch_Error_None")[0] - self.assertEqual(error_none_task.get_state(), TaskState.CANCELLED) + self.assertEqual(error_none_task.state, TaskState.CANCELLED) def testSubworkflowCancelEvent(self): @@ -56,13 +56,13 @@ class TransactionSubprocessTest(BpmnWorkflowTestCase): # Check that we completed the Cancel Task cancel_task = self.workflow.get_tasks_from_spec_name("Cancel_Action")[0] - self.assertEqual(cancel_task.get_state(), TaskState.COMPLETED) + self.assertEqual(cancel_task.state, TaskState.COMPLETED) # And cancelled the remaining tasks error_1_task = self.workflow.get_tasks_from_spec_name("Catch_Error_1")[0] - self.assertEqual(error_1_task.get_state(), TaskState.CANCELLED) + self.assertEqual(error_1_task.state, TaskState.CANCELLED) error_none_task = self.workflow.get_tasks_from_spec_name("Catch_Error_None")[0] - self.assertEqual(error_none_task.get_state(), TaskState.CANCELLED) + self.assertEqual(error_none_task.state, TaskState.CANCELLED) # We should not have this task, as we followed the 'cancel branch' print_task = self.workflow.get_tasks_from_spec_name("Activity_Print_Data") @@ -87,13 +87,13 @@ class TransactionSubprocessTest(BpmnWorkflowTestCase): # The cancel boundary event should be cancelled cancel_task = self.workflow.get_tasks_from_spec_name("Catch_Cancel_Event")[0] - self.assertEqual(cancel_task.get_state(), TaskState.CANCELLED) + self.assertEqual(cancel_task.state, TaskState.CANCELLED) # We should catch the None Error, but not Error 1 error_none_task = self.workflow.get_tasks_from_spec_name("Catch_Error_None")[0] - self.assertEqual(error_none_task.get_state(), TaskState.COMPLETED) + self.assertEqual(error_none_task.state, TaskState.COMPLETED) error_1_task = self.workflow.get_tasks_from_spec_name("Catch_Error_1")[0] - self.assertEqual(error_1_task.get_state(), TaskState.CANCELLED) + self.assertEqual(error_1_task.state, TaskState.CANCELLED) # Make sure this branch didn't getfollowed print_task = self.workflow.get_tasks_from_spec_name("Activity_Print_Data") @@ -117,9 +117,9 @@ class TransactionSubprocessTest(BpmnWorkflowTestCase): # Both boundary events should complete error_none_task = self.workflow.get_tasks_from_spec_name("Catch_Error_None")[0] - self.assertEqual(error_none_task.get_state(), TaskState.COMPLETED) + self.assertEqual(error_none_task.state, TaskState.COMPLETED) error_1_task = self.workflow.get_tasks_from_spec_name("Catch_Error_1")[0] - self.assertEqual(error_1_task.get_state(), TaskState.COMPLETED) + self.assertEqual(error_1_task.state, TaskState.COMPLETED) print_task = self.workflow.get_tasks_from_spec_name("Activity_Print_Data") self.assertEqual(len(print_task), 0) diff --git a/tests/SpiffWorkflow/bpmn/serializer/VersionMigrationTest.py b/tests/SpiffWorkflow/bpmn/serializer/VersionMigrationTest.py index cae051baf..2b169f149 100644 --- a/tests/SpiffWorkflow/bpmn/serializer/VersionMigrationTest.py +++ b/tests/SpiffWorkflow/bpmn/serializer/VersionMigrationTest.py @@ -4,15 +4,16 @@ import time from SpiffWorkflow.task import TaskState from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine from SpiffWorkflow.bpmn.PythonScriptEngineEnvironment import TaskDataEnvironment +from SpiffWorkflow.bpmn.serializer.migration.exceptions import VersionMigrationError from .BaseTestCase import BaseTestCase -class VersionMigrationTest(BaseTestCase): +class Version_1_0_Test(BaseTestCase): SERIALIZER_VERSION = "1.2" - def test_convert_1_0_to_1_1(self): + def test_convert_subprocess(self): # The serialization used here comes from NestedSubprocessTest saved at line 25 with version 1.0 fn = os.path.join(self.DATA_DIR, 'serialization', 'v1.0.json') wf = self.serializer.deserialize_json(open(fn).read()) @@ -23,10 +24,38 @@ class VersionMigrationTest(BaseTestCase): wf.do_engine_steps() self.assertEqual(True, wf.is_completed()) - def test_convert_1_1_to_1_2(self): - fn = os.path.join(self.DATA_DIR, 'serialization', 'v1-1.json') + +class Version_1_1_Test(BaseTestCase): + + def test_timers(self): + fn = os.path.join(self.DATA_DIR, 'serialization', 'v1.1-timers.json') wf = self.serializer.deserialize_json(open(fn).read()) wf.script_engine = PythonScriptEngine(environment=TaskDataEnvironment({"time": time})) wf.refresh_waiting_tasks() wf.do_engine_steps() self.assertTrue(wf.is_completed()) + + def test_convert_data_specs(self): + fn = os.path.join(self.DATA_DIR, 'serialization', 'v1.1-data.json') + wf = self.serializer.deserialize_json(open(fn).read()) + wf.do_engine_steps() + self.assertTrue(wf.is_completed()) + + def test_convert_exclusive_gateway(self): + fn = os.path.join(self.DATA_DIR, 'serialization', 'v1.1-gateways.json') + wf = self.serializer.deserialize_json(open(fn).read()) + wf.do_engine_steps() + task = wf.get_tasks_from_spec_name('Gateway_askQuestion')[0] + self.assertEqual(len(task.task_spec.cond_task_specs), 2) + ready_task = wf.get_ready_user_tasks()[0] + ready_task.data['NeedClarification'] = 'Yes' + ready_task.complete() + wf.do_engine_steps() + ready_task = wf.get_ready_user_tasks()[0] + self.assertEqual(ready_task.task_spec.name, 'Activity_A2') + + def test_check_multiinstance(self): + fn = os.path.join(self.DATA_DIR, 'serialization', 'v1.1-multi.json') + with self.assertRaises(VersionMigrationError) as ctx: + wf = self.serializer.deserialize_json(open(fn).read()) + self.assertEqual(ctx.exception.message, "This workflow cannot be migrated because it contains MultiInstance Tasks") \ No newline at end of file diff --git a/tests/SpiffWorkflow/camunda/DefaultGatewayPMITest.py b/tests/SpiffWorkflow/camunda/DefaultGatewayPMITest.py deleted file mode 100644 index 96852cc2c..000000000 --- a/tests/SpiffWorkflow/camunda/DefaultGatewayPMITest.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- - - -import unittest - -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow - -from tests.SpiffWorkflow.camunda.BaseTestCase import BaseTestCase - -__author__ = 'matth' - -class DefaultGatewayPMITest(BaseTestCase): - """The example bpmn diagram tests both a set cardinality from user input - as well as looping over an existing array.""" - - def setUp(self): - spec, subprocesses = self.load_workflow_spec('default_gateway_pmi.bpmn', 'DefaultGateway') - self.workflow = BpmnWorkflow(spec, subprocesses) - self.workflow.do_engine_steps() - - def testRunThroughHappy(self): - self.actual_test(False) - - def testRunThroughSaveRestore(self): - self.actual_test(True) - - def actual_test(self, save_restore=False): - - # Set initial array size to 3 in the first user form. - task = self.workflow.get_ready_user_tasks()[0] - self.assertEqual("DoStuff", task.task_spec.name) - task.update_data({"morestuff": 'Yep'}) - self.workflow.complete_task_from_id(task.id) - self.workflow.do_engine_steps() - if save_restore: self.save_restore() - - # Set the names of the 3 family members. - for i in range(3): - task = self.workflow.get_ready_user_tasks()[0] - if i == 0: - self.assertEqual("GetMoreStuff", task.task_spec.name) - else: - self.assertEqual("GetMoreStuff_%d"%(i-1), task.task_spec.name) - - - task.update_data({"stuff.addstuff": "Stuff %d"%i}) - self.workflow.complete_task_from_id(task.id) - if save_restore: self.save_restore() - self.workflow.do_engine_steps() - - if save_restore: self.save_restore() - self.assertTrue(self.workflow.is_completed()) - - - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(DefaultGatewayPMITest) - -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/camunda/ExclusiveGatewayPMITest.py b/tests/SpiffWorkflow/camunda/ExclusiveGatewayPMITest.py deleted file mode 100644 index 1b65ba575..000000000 --- a/tests/SpiffWorkflow/camunda/ExclusiveGatewayPMITest.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- coding: utf-8 -*- - -import unittest - -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow - -from tests.SpiffWorkflow.camunda.BaseTestCase import BaseTestCase - -__author__ = 'matth' - - -class ExclusiveGatewayPMITest(BaseTestCase): - """The example bpmn diagram tests both a set cardinality from user input - as well as looping over an existing array.""" - - def setUp(self): - spec, subprocesses = self.load_workflow_spec('default_gateway_pmi.bpmn', 'DefaultGateway') - self.workflow = BpmnWorkflow(spec, subprocesses) - - def testRunThroughHappy(self): - self.actual_test(False) - - def testRunThroughSaveRestore(self): - self.actual_test(True) - - def testRunThroughHappyNo(self): - self.actual_test(False,'No') - - def testRunThroughSaveRestoreNo(self): - self.actual_test(True,'No') - - def actual_test(self, save_restore=False,response='Yes'): - - self.workflow.do_engine_steps() - - # Set initial array size to 3 in the first user form. - task = self.workflow.get_ready_user_tasks()[0] - self.assertEqual("DoStuff", task.task_spec.name) - task.update_data({"morestuff": response}) - self.workflow.complete_task_from_id(task.id) - self.workflow.do_engine_steps() - if save_restore: self.save_restore() - - # Set the names of the 3 family members. - if response == 'Yes': - for i in range(3): - task = self.workflow.get_ready_user_tasks()[0] - if i == 0: - self.assertEqual("GetMoreStuff", task.task_spec.name) - else: - self.assertEqual("GetMoreStuff_%d"%(i-1), task.task_spec.name) - - - task.update_data({"stuff.addstuff": "Stuff %d"%i}) - self.workflow.complete_task_from_id(task.id) - if save_restore: self.save_restore() - self.workflow.do_engine_steps() - - if save_restore: self.save_restore() - self.assertTrue(self.workflow.is_completed()) - - - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(ExclusiveGatewayPMITest) - -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/camunda/MultiInstanceArrayTest.py b/tests/SpiffWorkflow/camunda/MultiInstanceArrayTest.py deleted file mode 100644 index 3244f16d3..000000000 --- a/tests/SpiffWorkflow/camunda/MultiInstanceArrayTest.py +++ /dev/null @@ -1,222 +0,0 @@ -# -*- coding: utf-8 -*- - -import unittest - -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from SpiffWorkflow.exceptions import WorkflowException - -from tests.SpiffWorkflow.camunda.BaseTestCase import BaseTestCase - -__author__ = 'matth' - - -class MultiInstanceArrayTest(BaseTestCase): - """The example bpmn diagram tests both a set cardinality from user input - as well as looping over an existing array.""" - - def setUp(self): - spec, subprocesses = self.load_workflow_spec('multi_instance_array.bpmn', 'MultiInstanceArray') - self.workflow = BpmnWorkflow(spec, subprocesses) - self.workflow.do_engine_steps() - - def testRunThroughHappy(self): - self.actual_test(False) - - def testRunThroughSaveRestore(self): - self.actual_test(True) - - - def testRunThroughHappyList(self): - self.actual_test2(False) - - def testRunThroughSaveRestoreList(self): - self.actual_test2(True) - - def testRunThroughHappyDict(self): - self.actual_test_with_dict(False) - - def testRunThroughSaveRestoreDict(self): - self.actual_test_with_dict(True) - - def testGetTaskExtensions(self): - self.actual_test_for_extensions(False) - - - def actual_test(self, save_restore=False): - - # Set initial array size to 3 in the first user form. - task = self.workflow.get_ready_user_tasks()[0] - taskinfo = task.task_info() - self.assertEqual(taskinfo,{'is_looping':False, - 'is_sequential_mi':False, - 'is_parallel_mi':False, - 'mi_count':0, - 'mi_index':0}) - self.assertEqual("Activity_FamSize", task.task_spec.name) - task.update_data({"Family": {"Size": 3}}) - self.workflow.complete_task_from_id(task.id) - if save_restore: self.save_restore() - - # Set the names of the 3 family members. - for i in range(3): - task = self.workflow.get_ready_user_tasks()[0] - taskinfo = task.task_info() - self.assertEqual(taskinfo, {'is_looping': False, - 'is_sequential_mi': True, - 'is_parallel_mi': False, - 'mi_count': 3, - 'mi_index': i+1}) - if i > 0: - self.assertEqual("FamilyMemberTask"+"_%d"%(i-1), task.task_spec.name) - else: - self.assertEqual("FamilyMemberTask", task.task_spec.name) - - - task.update_data({"FamilyMember": {"FirstName": "The Funk #%i" % i}}) - self.workflow.complete_task_from_id(task.id) - if save_restore: self.save_restore() - self.workflow.do_engine_steps() - - self.assertEqual({'1': {'FirstName': 'The Funk #0'}, - '2': {'FirstName': 'The Funk #1'}, - '3': {'FirstName': 'The Funk #2'}}, - task.data["Family"]["Members"]) - #### NB - start here - ### Data is not correctly getting to the next task upon complete of the last task - ### after do_engine_steps, the next task in the list should be the same as task.data - ### but it is not. - - ### invalid copy of data?? ## appears that parent is not hooked up correctly - - # Set the birthdays of the 3 family members. - for i in range(3): - task = self.workflow.get_ready_user_tasks()[0] - if i > 0: - self.assertEqual("FamilyMemberBday"+"_%d"%(i-1), task.task_spec.name) - else: - self.assertEqual("FamilyMemberBday", task.task_spec.name) - task.update_data({"CurrentFamilyMember": {"Birthdate": "10/0%i/1985" % i}}) - self.workflow.complete_task_from_id(task.id) - if save_restore: self.save_restore() - self.workflow.do_engine_steps() - - self.workflow.do_engine_steps() - if save_restore: self.save_restore() - self.assertTrue(self.workflow.is_completed()) - - self.assertEqual({'1': {'FirstName': 'The Funk #0', "Birthdate": "10/00/1985"}, - '2': {'FirstName': 'The Funk #1', "Birthdate": "10/01/1985"}, - '3': {'FirstName': 'The Funk #2', "Birthdate": "10/02/1985"}}, - self.workflow.last_task.data["Family"]["Members"]) - - - - - def actual_test2(self, save_restore=False): - - # Set initial array size to 3 in the first user form. - task = self.workflow.get_ready_user_tasks()[0] - self.assertEqual("Activity_FamSize", task.task_spec.name) - task.update_data({"Family":{"Size": 3}}) - self.workflow.complete_task_from_id(task.id) - if save_restore: self.save_restore() - - # Set the names of the 3 family members. - for i in range(3): - task = self.workflow.get_ready_user_tasks()[0] - if i > 0: - self.assertEqual("FamilyMemberTask"+"_%d"%(i-1), task.task_spec.name) - else: - self.assertEqual("FamilyMemberTask", task.task_spec.name) - task.update_data({"FamilyMember": {"FirstName": "The Funk #%i" % i}}) - self.workflow.complete_task_from_id(task.id) - if save_restore: self.save_restore() - - self.assertEqual({'1': {'FirstName': 'The Funk #0'}, - '2': {'FirstName': 'The Funk #1'}, - '3': {'FirstName': 'The Funk #2'}}, - task.data["Family"]["Members"]) - - - # Make sure that if we have a list as both input and output - # collection, that we raise an exception - - task = self.workflow.get_ready_user_tasks()[0] - task.data['Family']['Members'] = ['The Funk #0','The Funk #1','The Funk #2'] - self.assertEqual("FamilyMemberBday", task.task_spec.name) - task.update_data( - {"CurrentFamilyMember": {"Birthdate": "10/0%i/1985" % i}}) - with self.assertRaises(WorkflowException) as context: - self.workflow.complete_task_from_id(task.id) - - - def actual_test_with_dict(self, save_restore=False): - - # Set initial array size to 3 in the first user form. - task = self.workflow.get_ready_user_tasks()[0] - self.assertEqual("Activity_FamSize", task.task_spec.name) - task.update_data({"Family":{"Size": 3}}) - self.workflow.complete_task_from_id(task.id) - if save_restore: self.save_restore() - - # Set the names of the 3 family members. - for i in range(3): - task = self.workflow.get_ready_user_tasks()[0] - if i > 0: - self.assertEqual("FamilyMemberTask"+"_%d"%(i-1), task.task_spec.name) - else: - self.assertEqual("FamilyMemberTask", task.task_spec.name) - task.update_data({"FamilyMember": {"FirstName": "The Funk #%i" % i}}) - self.workflow.complete_task_from_id(task.id) - if save_restore: self.save_restore() - - self.assertEqual({'1': {'FirstName': 'The Funk #0'}, - '2': {'FirstName': 'The Funk #1'}, - '3': {'FirstName': 'The Funk #2'}}, - task.data["Family"]["Members"]) - - - - # Set the birthdays of the 3 family members. - for i in range(3): - task = self.workflow.get_ready_user_tasks()[0] - if i == 0: - # Modify so that the dict keys are alpha rather than int - task.data["Family"]["Members"] = { - "a": {'FirstName': 'The Funk #0'}, - "b": {'FirstName': 'The Funk #1'}, - "c": {'FirstName': 'The Funk #2'}} - if (i > 0): - self.assertEqual("FamilyMemberBday"+"_%d"%(i-1), task.task_spec.name) - else: - self.assertEqual("FamilyMemberBday", task.task_spec.name) - task.update_data( - {"CurrentFamilyMember": {"Birthdate": "10/0%i/1985" % i}}) - self.workflow.complete_task_from_id(task.id) -# if save_restore: self.save_restore() - - self.workflow.do_engine_steps() - if save_restore: self.save_restore() - self.assertTrue(self.workflow.is_completed()) - - self.assertEqual({"a": {'FirstName': 'The Funk #0', "Birthdate": "10/00/1985"}, - "b": {'FirstName': 'The Funk #1', "Birthdate": "10/01/1985"}, - "c": {'FirstName': 'The Funk #2', "Birthdate": "10/02/1985"}}, - self.workflow.last_task.data["Family"]["Members"]) - - - - def actual_test_for_extensions(self, save_restore=False): - - # Set initial array size to 3 in the first user form. - task = self.workflow.get_ready_user_tasks()[0] - self.assertEqual("Activity_FamSize", task.task_spec.name) - extensions = task.task_spec.extensions # assume bpmn - self.assertEqual(extensions,{'Test1':'Value1','Test2':'Value2'}) - - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(MultiInstanceArrayTest) - -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/camunda/MultiInstanceDMNTest.py b/tests/SpiffWorkflow/camunda/MultiInstanceDMNTest.py index e31aa083b..d0893c0e5 100644 --- a/tests/SpiffWorkflow/camunda/MultiInstanceDMNTest.py +++ b/tests/SpiffWorkflow/camunda/MultiInstanceDMNTest.py @@ -15,32 +15,21 @@ class MultiInstanceDMNTest(BaseTestCase): self.script_engine = PythonScriptEngine(environment=BoxedTaskDataEnvironment()) self.workflow.script_engine = self.script_engine - def testConstructor(self): - pass # this is accomplished through setup. - def testDmnHappy(self): - self.workflow.do_engine_steps() - self.workflow.complete_next() - self.workflow.do_engine_steps() - self.workflow.complete_next() self.workflow.do_engine_steps() self.assertEqual(self.workflow.data['stuff']['E']['y'], 'D') - def testDmnSaveRestore(self): + self.save_restore() - self.workflow.script_engine = self.script_engine self.workflow.do_engine_steps() self.workflow.complete_next() self.save_restore() - self.workflow.script_engine = self.script_engine self.workflow.do_engine_steps() self.workflow.complete_next() self.save_restore() - self.workflow.script_engine = self.script_engine self.workflow.do_engine_steps() self.save_restore() - self.workflow.script_engine = self.script_engine self.assertEqual(self.workflow.data['stuff']['E']['y'], 'D') diff --git a/tests/SpiffWorkflow/camunda/MultiInstanceDeepDictEdit.py b/tests/SpiffWorkflow/camunda/MultiInstanceDeepDictEdit.py deleted file mode 100644 index 34b3db468..000000000 --- a/tests/SpiffWorkflow/camunda/MultiInstanceDeepDictEdit.py +++ /dev/null @@ -1,113 +0,0 @@ -# -*- coding: utf-8 -*- - - - - -import copy -import sys -import os -import unittest -sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -__author__ = 'matth' - -from tests.SpiffWorkflow.camunda.BaseTestCase import BaseTestCase - - -class MultiInstanceDeepDictTest(BaseTestCase): - """The example bpmn diagram tests both a set cardinality from user input - as well as looping over an existing array.""" - - deep_dict = { - "StudyInfo": { - "investigators": { - "PI": { - "affiliation": "", - "department": "", - "display_name": "Daniel Harold Funk", - "email": "dhf8r@virginia.edu", - "given_name": "Daniel", - "sponsor_type": "Contractor", - "telephone_number": "", - "title": "", - "type_full": "Primary Investigator", - "user_id": "dhf8r" - }, - "DC": { - "type_full": "Department Contact", - "user_id": "John Smith" - } - } - } - } - - expected_result = copy.copy(deep_dict) - expected_result["StudyInfo"]["investigators"]["DC"]["email"] = "john.smith@gmail.com" - expected_result["StudyInfo"]["investigators"]["PI"]["email"] = "dan.funk@gmail.com" - - def setUp(self): - self.spec = self.load_workflow_spec( - 'data/multi_instance_parallel_deep_data_edit.bpmn', - 'MultiInstance') - - def testRunThroughHappy(self): - self.actual_test(False) - - def testRunThroughSaveRestore(self): - self.actual_test(True) - - def actual_test(self, save_restore=False): - - self.workflow = BpmnWorkflow(self.spec) - self.workflow.do_engine_steps() - if save_restore: self.save_restore() - - # The initial task is a script task. Set the data there - # and move one. - task = self.workflow.get_ready_user_tasks()[0] - task.data = self.deep_dict - self.workflow.complete_task_from_id(task.id) - self.workflow.do_engine_steps() - if save_restore: self.save_restore() - - task = self.workflow.get_ready_user_tasks()[0] - taskinfo = task.task_info() - self.assertEqual(taskinfo,{'is_looping':False, - 'is_sequential_mi':False, - 'is_parallel_mi':True, - 'mi_count':2, - 'mi_index':1}) - self.assertEqual("MultiInstanceTask", task.task_spec.name) - self.assertTrue("investigator" in task.data) - data = copy.copy(task.data) - data['investigator']['email'] = "john.smith@gmail.com" - task.update_data(data) - self.workflow.complete_task_from_id(task.id) - if save_restore: self.save_restore() - - - task = self.workflow.get_ready_user_tasks()[0] - taskinfo = task.task_info() - self.assertEqual(taskinfo,{'is_looping':False, - 'is_sequential_mi':False, - 'is_parallel_mi':True, - 'mi_count':2, - 'mi_index':2}) - self.assertEqual("MultiInstanceTask", task.task_spec.name) - self.assertTrue("investigator" in task.data) - data = copy.copy(task.data) - data['investigator']['email'] = "dan.funk@gmail.com" - task.update_data(data) - self.workflow.complete_task_from_id(task.id) - self.workflow.do_engine_steps() - if save_restore: self.save_restore() - - self.assertTrue(self.workflow.is_completed()) - task = self.workflow.last_task - self.assertEqual(self.expected_result, task.data) - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(MultiInstanceDeepDictTest) - -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/camunda/MultiInstanceParallelArrayTest.py b/tests/SpiffWorkflow/camunda/MultiInstanceParallelArrayTest.py deleted file mode 100644 index 14373b0c3..000000000 --- a/tests/SpiffWorkflow/camunda/MultiInstanceParallelArrayTest.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- coding: utf-8 -*- - -import unittest -import random - -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from tests.SpiffWorkflow.camunda.BaseTestCase import BaseTestCase - -__author__ = 'matth' - -debug = True - -class MultiInstanceParallelArrayTest(BaseTestCase): - """The example bpmn diagram tests both a set cardinality from user input - as well as looping over an existing array.""" - - def setUp(self): - spec, subprocesses = self.load_workflow_spec('multi_instance_array_parallel.bpmn', 'MultiInstanceArray') - self.workflow = BpmnWorkflow(spec, subprocesses) - - def testRunThroughHappy(self): - self.actual_test(False) - - def testRunThroughSaveRestore(self): - self.actual_test(True) - - def actual_test(self, save_restore=False): - - first_task = self.workflow.task_tree - - # A previous task (in this case the root task) will set the data - # so it must be found later. - first_task.update_data({"FamilySize": 3}) - self.workflow.do_engine_steps() - if save_restore: self.reload_save_restore() - # Set initial array size to 3 in the first user form. - task = self.workflow.get_ready_user_tasks()[0] - self.assertEqual("Activity_FamSize", task.task_spec.name) - task.update_data({"FamilySize": 3}) - self.workflow.complete_task_from_id(task.id) - if save_restore: self.reload_save_restore() - self.workflow.do_engine_steps() - - # Set the names of the 3 family members. - for i in range(3): - - tasks = self.workflow.get_ready_user_tasks() - self.assertEqual(len(tasks),1) # still with sequential MI - task = tasks[0] - if i > 0: - self.assertEqual("FamilyMemberTask"+"_%d"%(i-1), task.task_spec.name) - else: - self.assertEqual("FamilyMemberTask", task.task_spec.name) - task.update_data({"FamilyMember": {"FirstName": "The Funk #%i" % i}}) - self.workflow.complete_task_from_id(task.id) - self.workflow.do_engine_steps() - if save_restore: - self.reload_save_restore() - tasks = self.workflow.get_ready_user_tasks() - - self.assertEqual(3,len(tasks)) - # Set the birthdays of the 3 family members. - for i in range(3): # emulate random Access - task = random.choice(tasks) - x = task.internal_data['runtimes'] -1 - self.assertEqual("FamilyMemberBday", task.task_spec.name[:16]) - self.assertEqual({"FirstName": "The Funk #%i" % x}, - task.data["CurrentFamilyMember"]) - task.update_data( - {"CurrentFamilyMember": {"Birthdate": "10/05/1985" + str(x)}}) - self.workflow.do_engine_steps() - self.workflow.complete_task_from_id(task.id) - # We used to check that the current data variable was available in the task, - # but there's no reason to preserve it after the task completes. We removed it - # in some cases and left it in others, which just adds to the confusion. - self.workflow.do_engine_steps() - if save_restore: - self.reload_save_restore() - self.workflow.do_engine_steps() - - tasks = self.workflow.get_ready_user_tasks() - - self.workflow.do_engine_steps() - if save_restore: - self.reload_save_restore() - - names = task.data['FamilyMembers'] - bdays = task.data['FamilyMemberBirthday'] - for x in list(names.keys()): - self.assertEqual(str(names[x]['FirstName'][-1]),str(bdays[x]['Birthdate'][-1])) - self.assertTrue(self.workflow.is_completed()) - - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(MultiInstanceParallelArrayTest) - -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/camunda/ParseMultiInstanceTest.py b/tests/SpiffWorkflow/camunda/ParseMultiInstanceTest.py new file mode 100644 index 000000000..9f612a6d8 --- /dev/null +++ b/tests/SpiffWorkflow/camunda/ParseMultiInstanceTest.py @@ -0,0 +1,91 @@ +from SpiffWorkflow.bpmn.workflow import BpmnWorkflow + +from .BaseTestCase import BaseTestCase + +# NB: I realize this is bad form, but MultiInstanceDMNTest uses a sequential MI task so I'm not adding tests +# for that here. The task specs are updated the same way, so this should be sufficient. +# I'm not testing the specific of operation here either, because that is pretty extensively tested in the +# main BPMN package + +class ParseMultiInstanceTest(BaseTestCase): + + def testCollectionInCardinality(self): + + spec, subprocesses = self.load_workflow_spec('parallel_multiinstance_cardinality.bpmn', 'main') + self.workflow = BpmnWorkflow(spec) + start = self.workflow.get_tasks_from_spec_name('Start')[0] + start.data = {'input_data': [1, 2, 3]} + self.workflow.do_engine_steps() + + self.save_restore() + + task_spec = self.workflow.get_tasks_from_spec_name('any_task')[0].task_spec + self.assertEqual(task_spec.data_input.name, 'input_data') + self.assertEqual(task_spec.data_output.name, 'output_data') + self.assertEqual(task_spec.input_item.name, 'output_item') + self.assertEqual(task_spec.output_item.name, 'output_item') + + ready_tasks = self.workflow.get_ready_user_tasks() + self.assertEqual(len(ready_tasks), 3) + + ready_tasks = self.workflow.get_ready_user_tasks() + self.assertEqual(len(ready_tasks), 3) + for task in ready_tasks: + task.data['output_item'] = task.data['output_item'] * 2 + task.complete() + + self.workflow.do_engine_steps() + self.assertTrue(self.workflow.is_completed()) + self.assertDictEqual(self.workflow.data, {'input_data': [1, 2, 3], 'output_data': [2, 4, 6]}) + + def testIntegerCardinality(self): + + spec, subprocesses = self.load_workflow_spec('parallel_multiinstance_cardinality.bpmn', 'main') + self.workflow = BpmnWorkflow(spec) + task_spec = self.workflow.get_tasks_from_spec_name('any_task')[0].task_spec + task_spec.cardinality = 'len(input_data)' + + start = self.workflow.get_tasks_from_spec_name('Start')[0] + start.data = {'input_data': [1, 2, 3]} + self.workflow.do_engine_steps() + + self.save_restore() + + self.assertEqual(task_spec.data_input, None) + self.assertEqual(task_spec.input_item.name, 'output_item') + + ready_tasks = self.workflow.get_ready_user_tasks() + self.assertEqual(len(ready_tasks), 3) + for task in ready_tasks: + task.data['output_item'] = task.data['output_item'] * 2 + task.complete() + + self.workflow.do_engine_steps() + self.assertTrue(self.workflow.is_completed()) + self.assertDictEqual(self.workflow.data, {'input_data': [1, 2, 3], 'output_data': [0, 2, 4]}) + + def testCollection(self): + + spec, subprocesses = self.load_workflow_spec('parallel_multiinstance_collection.bpmn', 'main') + self.workflow = BpmnWorkflow(spec) + start = self.workflow.get_tasks_from_spec_name('Start')[0] + start.data = {'input_data': [1, 2, 3]} + self.workflow.do_engine_steps() + + self.save_restore() + + task_spec = self.workflow.get_tasks_from_spec_name('any_task')[0].task_spec + self.assertEqual(task_spec.data_input.name, 'input_data') + self.assertEqual(task_spec.data_output.name, 'input_data') + self.assertEqual(task_spec.input_item.name, 'input_item') + self.assertEqual(task_spec.output_item.name, 'input_item') + + ready_tasks = self.workflow.get_ready_user_tasks() + self.assertEqual(len(ready_tasks), 3) + for task in ready_tasks: + task.data['input_item'] = task.data['input_item'] * 2 + task.complete() + + self.workflow.do_engine_steps() + self.assertTrue(self.workflow.is_completed()) + self.assertDictEqual(self.workflow.data, {'input_data': [2, 4, 6]}) diff --git a/tests/SpiffWorkflow/camunda/ResetTokenMIParallelTest.py b/tests/SpiffWorkflow/camunda/ResetTokenMIParallelTest.py deleted file mode 100644 index 75f2df361..000000000 --- a/tests/SpiffWorkflow/camunda/ResetTokenMIParallelTest.py +++ /dev/null @@ -1,80 +0,0 @@ -# -*- coding: utf-8 -*- - -import unittest - -from tests.SpiffWorkflow.camunda.BaseTestCase import BaseTestCase -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow - -__author__ = 'kellym' - -class ResetTokenTestMIParallel(BaseTestCase): - """The example bpmn diagram tests both a set cardinality from user input - as well as looping over an existing array.""" - - def setUp(self): - spec, subprocesses = self.load_workflow_spec('token_trial_MIParallel.bpmn', 'token') - self.workflow = BpmnWorkflow(spec, subprocesses) - - def testRunThroughHappy(self): - self.actual_test(save_restore=False) - - def testRunThroughSaveRestore(self): - self.actual_test(save_restore=True) - - def actual_test(self, save_restore=False,reset_data=False): - - self.workflow.do_engine_steps() - firsttaskid = None - steps = [{'taskname':'First', - 'task_data': {'do_step':'Yes'}}, - {'taskname': 'FormA', - 'task_data': {'current': {'A' : 'x'}}}, - {'taskname': 'FormA', - 'task_data': {'current': {'A' : 'y'}}}, - {'taskname': 'FormA', - 'task_data': {'current': {'A' : 'z'}}} - ] - for step in steps: - task = self.workflow.get_ready_user_tasks()[0] - if firsttaskid == None and step['taskname']=='FormA': - firsttaskid = task.id - self.assertEqual(step['taskname'], task.task_spec.name[:len(step['taskname'])]) - task.update_data(step['task_data']) - self.workflow.complete_task_from_id(task.id) - self.workflow.do_engine_steps() - if save_restore: self.save_restore() - - self.assertEqual({'do_step': 'Yes', - 'output': {'1': {'A': 'x'}, '2': {'A': 'y'}, '3': {'A': 'z'}}}, - self.workflow.last_task.data) - - self.workflow.reset_task_from_id(firsttaskid) - #NB - this won't test random access - steps = [{'taskname': 'FormA', - 'task_data': {'current': {'A' : 'a1'}}}, - {'taskname': 'FormC', - 'task_data': {'C' : 'c'}}, - ] - for step in steps: - task = self.workflow.get_ready_user_tasks()[0] - self.assertEqual(step['taskname'], task.task_spec.name) - task.update_data(step['task_data']) - self.workflow.complete_task_from_id(task.id) - self.workflow.do_engine_steps() - if save_restore: self.save_restore() - - self.assertTrue(self.workflow.is_completed()) - - self.assertEqual({'do_step': 'Yes', - 'C': 'c', - 'output': {'1': {'A': 'a1'}, - '2': {'A': 'y'}, - '3': {'A': 'z'}}}, - self.workflow.last_task.data) - - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(ResetTokenTestMIParallel) - -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/camunda/ResetTokenMITest.py b/tests/SpiffWorkflow/camunda/ResetTokenMITest.py deleted file mode 100644 index 5d6c2e27e..000000000 --- a/tests/SpiffWorkflow/camunda/ResetTokenMITest.py +++ /dev/null @@ -1,81 +0,0 @@ -# -*- coding: utf-8 -*- - -import unittest - -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from tests.SpiffWorkflow.camunda.BaseTestCase import BaseTestCase - -__author__ = 'kellym' - -class ResetTokenTestMI(BaseTestCase): - """The example bpmn diagram tests both a set cardinality from user input - as well as looping over an existing array.""" - - def setUp(self): - spec, subprocesses = self.load_workflow_spec('token_trial_MI.bpmn', 'token') - self.workflow = BpmnWorkflow(spec, subprocesses) - - def testRunThroughHappy(self): - self.actual_test(save_restore=False) - - def testRunThroughSaveRestore(self): - self.actual_test(save_restore=True) - - def actual_test(self, save_restore=False,reset_data=False): - - self.workflow.do_engine_steps() - firsttaskid = None - steps = [{'taskname':'First', - 'task_data': {'do_step':'Yes'}}, - {'taskname': 'FormA', - 'task_data': {'current': {'A' : 'x'}}}, - {'taskname': 'FormA_0', - 'task_data': {'current': {'A' : 'y'}}}, - {'taskname': 'FormA_1', - 'task_data': {'current': {'A' : 'z'}}} - ] - for step in steps: - task = self.workflow.get_ready_user_tasks()[0] - if firsttaskid == None and step['taskname']=='FormA': - firsttaskid = task.id - self.assertEqual(step['taskname'], task.task_spec.name) - task.update_data(step['task_data']) - self.workflow.complete_task_from_id(task.id) - self.workflow.do_engine_steps() - if save_restore: self.save_restore() - - self.workflow.reset_task_from_id(firsttaskid) - - steps = [{'taskname': 'FormA', - 'task_data': {'current': {'A': 'a1'}}}, - {'taskname': 'FormA_0', - 'task_data': {'current': {'A': 'a2'}}}, - {'taskname': 'FormA_1', - 'task_data': {'current': {'A': 'a3'}}}, - {'taskname': 'FormC', - 'task_data': {'C': 'c'}} - ] - - for step in steps: - task = self.workflow.get_ready_user_tasks()[0] - self.assertEqual(step['taskname'], task.task_spec.name) - task.update_data(step['task_data']) - self.workflow.complete_task_from_id(task.id) - self.workflow.do_engine_steps() - if save_restore: self.save_restore() - - self.assertTrue(self.workflow.is_completed()) - self.assertEqual({'do_step': 'Yes', - 'output': {'1': {'A': 'a1'}, - '2': {'A': 'a2'}, - '3': {'A': 'a3'}}, - 'C': 'c'}, - self.workflow.last_task.data) - - - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(ResetTokenTestMI) - -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/camunda/data/DMNMultiInstance.bpmn b/tests/SpiffWorkflow/camunda/data/DMNMultiInstance.bpmn index d00fd87d2..acc7f2fbe 100644 --- a/tests/SpiffWorkflow/camunda/data/DMNMultiInstance.bpmn +++ b/tests/SpiffWorkflow/camunda/data/DMNMultiInstance.bpmn @@ -1,27 +1,20 @@ - + Flow_1b29lxw - Flow_0fusz9y + SequenceFlow_06fnqj2 - + - Flow_0z7tfh1 + Flow_09ciw49 SequenceFlow_06fnqj2 - - - Flow_066d5e1 - Flow_0fusz9y - print('EndScript') -print(stuff) - - + This is a test of documentation @@ -33,55 +26,24 @@ of documentation 'D': {'x': 6}, 'E': {'x': 7}} - - - Flow_09ciw49 - Flow_0z7tfh1 - - - - SequenceFlow_06fnqj2 - Flow_066d5e1 - - - - - - - - - - - - - - + - - + + - - - - - - - - - @@ -91,15 +53,15 @@ of documentation + + + - + - - - diff --git a/tests/SpiffWorkflow/camunda/data/common_workflow.bpmn b/tests/SpiffWorkflow/camunda/data/common_workflow.bpmn deleted file mode 100644 index 3902b9b4a..000000000 --- a/tests/SpiffWorkflow/camunda/data/common_workflow.bpmn +++ /dev/null @@ -1,89 +0,0 @@ - - - - - Flow_0xpz6la - Flow_03yam6h - my_custom_function('test 1 from common workflow') - - - Flow_1jz376x - - - - - - - - - Flow_03yam6h - Flow_0pc6yx9 - - - - Flow_0pc6yx9 - Flow_16t7ue6 - my_custom_function('test 2 from common workflow') - - - - - - - - - - - - - Flow_16t7ue6 - Flow_1jz376x - - - Flow_0xpz6la - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/camunda/data/default_gateway_pmi.bpmn b/tests/SpiffWorkflow/camunda/data/default_gateway_pmi.bpmn deleted file mode 100644 index d98baf5d8..000000000 --- a/tests/SpiffWorkflow/camunda/data/default_gateway_pmi.bpmn +++ /dev/null @@ -1,89 +0,0 @@ - - - - - Flow_1wis1un - - - - - - - - Flow_1wis1un - Flow_144jxvd - - - - Flow_144jxvd - Flow_1riszc2 - Flow_0xdvee4 - - - - - Flow_13ncefd - Flow_0xdvee4 - - - - - - - - - Flow_1riszc2 - Flow_13ncefd - - 3 - - - - morestuff == 'No' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/camunda/data/multi_instance_array.bpmn b/tests/SpiffWorkflow/camunda/data/multi_instance_array.bpmn deleted file mode 100644 index f37b7e525..000000000 --- a/tests/SpiffWorkflow/camunda/data/multi_instance_array.bpmn +++ /dev/null @@ -1,99 +0,0 @@ - - - - - Flow_0bplvtg - - - Please enter family size: - - - - - - - - - - - - - - - - - - - - Flow_0bplvtg - Flow_0zpm0rc - - - - Please enter information for family member {{ FamilyMember }}: - - - - - - Flow_0zpm0rc - Flow_0659lqh - - Family.Size - - - - - Enter Birthday for {{ CurrentFamilyMember['FamilyMember.FormField_FirstName'] }} - - - - - - Flow_0659lqh - Flow_0ncqf54 - - - - - - XXX - Flow_0ncqf54 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/camunda/data/multi_instance_array_parallel.bpmn b/tests/SpiffWorkflow/camunda/data/multi_instance_array_parallel.bpmn deleted file mode 100644 index fbcd2cf1d..000000000 --- a/tests/SpiffWorkflow/camunda/data/multi_instance_array_parallel.bpmn +++ /dev/null @@ -1,99 +0,0 @@ - - - - - Flow_0bplvtg - - - Please enter family size: - - - - - - - - - - - - - - - - Flow_0bplvtg - Flow_0zpm0rc - - - - Please enter information for family member {{ FamilyMember }}: - - - - - - Flow_0zpm0rc - Flow_0659lqh - - FamilySize - - - - - Enter Birthday for {{ CurrentFamilyMember['FamilyMember.FormField_FirstName'] }} - - - - - - Flow_0659lqh - Flow_0ncqf54 - - FamilyMembers - - - - - - XXX - Flow_0ncqf54 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/camunda/data/multi_instance_parallel_deep_data_edit.bpmn b/tests/SpiffWorkflow/camunda/data/multi_instance_parallel_deep_data_edit.bpmn deleted file mode 100644 index 7ce994be9..000000000 --- a/tests/SpiffWorkflow/camunda/data/multi_instance_parallel_deep_data_edit.bpmn +++ /dev/null @@ -1,66 +0,0 @@ - - - - - Flow_0t6p1sb - - - - Flow_0ugjw69 - - - - # Please provide addtional information about: -## Investigator ID: {{investigator.user_id}} -## Role: {{investigator.type_full}} - - - - - - SequenceFlow_1p568pp - Flow_0ugjw69 - - - - - Imagine a script task here that loads a complex data set. - Flow_0t6p1sb - SequenceFlow_1p568pp - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/camunda/data/parallel_multiinstance_cardinality.bpmn b/tests/SpiffWorkflow/camunda/data/parallel_multiinstance_cardinality.bpmn new file mode 100644 index 000000000..75eccb29a --- /dev/null +++ b/tests/SpiffWorkflow/camunda/data/parallel_multiinstance_cardinality.bpmn @@ -0,0 +1,41 @@ + + + + + Flow_0m77cxj + + + Flow_0m77cxj + Flow_1jbp2el + + input_data + + + + + Flow_1jbp2el + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/camunda/data/parallel_multiinstance_collection.bpmn b/tests/SpiffWorkflow/camunda/data/parallel_multiinstance_collection.bpmn new file mode 100644 index 000000000..0fbc788c6 --- /dev/null +++ b/tests/SpiffWorkflow/camunda/data/parallel_multiinstance_collection.bpmn @@ -0,0 +1,39 @@ + + + + + Flow_0m77cxj + + + Flow_0m77cxj + Flow_1jbp2el + + + + + Flow_1jbp2el + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/camunda/data/token_trial_MI.bpmn b/tests/SpiffWorkflow/camunda/data/token_trial_MI.bpmn deleted file mode 100644 index 368cd4f08..000000000 --- a/tests/SpiffWorkflow/camunda/data/token_trial_MI.bpmn +++ /dev/null @@ -1,83 +0,0 @@ - - - - - Flow_03vnrmv - - - Do you want to do the next steps? - - - - - - Flow_03vnrmv - Flow_10pdq2v - - - FormC - - - - - - Flow_0ztfesh - Flow_039y4lk - - - - Flow_039y4lk - - - - MI item - - - - - - Flow_10pdq2v - Flow_0ztfesh - - 3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/camunda/data/token_trial_MIParallel.bpmn b/tests/SpiffWorkflow/camunda/data/token_trial_MIParallel.bpmn deleted file mode 100644 index 3e2f1b19b..000000000 --- a/tests/SpiffWorkflow/camunda/data/token_trial_MIParallel.bpmn +++ /dev/null @@ -1,83 +0,0 @@ - - - - - Flow_03vnrmv - - - Do you want to do the next steps? - - - - - - Flow_03vnrmv - Flow_10pdq2v - - - FormC - - - - - - Flow_0ztfesh - Flow_039y4lk - - - - Flow_039y4lk - - - - MI item - - - - - - Flow_10pdq2v - Flow_0ztfesh - - 3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/SpiffWorkflow/specs/ExecuteTest.py b/tests/SpiffWorkflow/specs/ExecuteTest.py index 05653e185..3a10ae75d 100644 --- a/tests/SpiffWorkflow/specs/ExecuteTest.py +++ b/tests/SpiffWorkflow/specs/ExecuteTest.py @@ -40,10 +40,7 @@ class ExecuteTest(TaskSpecTest): expected = 'Start\n testtask\n' workflow = run_workflow(self, self.wf_spec, expected, '') task = workflow.get_tasks_from_spec_name('testtask')[0] - self.assertEqual(task.state_history, [TaskState.FUTURE, - TaskState.WAITING, - TaskState.READY, - TaskState.COMPLETED]) + self.assertEqual(task.state, TaskState.COMPLETED) self.assertIn(b'127.0.0.1', task.results[0]) diff --git a/tests/SpiffWorkflow/specs/TaskSpecTest.py b/tests/SpiffWorkflow/specs/TaskSpecTest.py index 2509d6184..717846566 100644 --- a/tests/SpiffWorkflow/specs/TaskSpecTest.py +++ b/tests/SpiffWorkflow/specs/TaskSpecTest.py @@ -52,14 +52,6 @@ class TaskSpecTest(unittest.TestCase): self.assertEqual(self.spec.outputs, [spec]) self.assertEqual(spec.inputs, [self.spec]) - def testFollow(self): - self.assertEqual(self.spec.outputs, []) - self.assertEqual(self.spec.inputs, []) - spec = self.create_instance() - self.spec.follow(spec) - self.assertEqual(spec.outputs, [self.spec]) - self.assertEqual(self.spec.inputs, [spec]) - def testTest(self): # Should fail because the TaskSpec has no id yet. spec = self.create_instance() @@ -101,12 +93,12 @@ class TaskSpecTest(unittest.TestCase): M = Join(self.wf_spec, 'M') T3 = Simple(self.wf_spec, 'T3') - T1.follow(self.wf_spec.start) - T2A.follow(T1) - T2B.follow(T1) + self.wf_spec.start.connect(T1) + T1.connect(T2A) + T1.connect(T2B) T2A.connect(M) T2B.connect(M) - T3.follow(M) + M.connect(T3) self.assertEqual(T1.ancestors(), [self.wf_spec.start]) self.assertEqual(T2A.ancestors(), [T1, self.wf_spec.start]) @@ -118,8 +110,7 @@ class TaskSpecTest(unittest.TestCase): T1 = Join(self.wf_spec, 'T1') T2 = Simple(self.wf_spec, 'T2') - T1.follow(self.wf_spec.start) - T2.follow(T1) + self.wf_spec.start.connect(T1) T1.connect(T2) self.assertEqual(T1.ancestors(), [self.wf_spec.start]) diff --git a/tests/SpiffWorkflow/specs/WorkflowSpecTest.py b/tests/SpiffWorkflow/specs/WorkflowSpecTest.py index 9b4c0d322..c2a5638e4 100644 --- a/tests/SpiffWorkflow/specs/WorkflowSpecTest.py +++ b/tests/SpiffWorkflow/specs/WorkflowSpecTest.py @@ -102,8 +102,8 @@ class WorkflowSpecTest(unittest.TestCase): task2 = Join(self.wf_spec, 'Second') task1.connect(task2) - task2.follow(task1) - task1.follow(task2) + task1.connect(task2) + task2.connect(task1) results = self.wf_spec.validate() self.assertIn("Found loop with 'Second': Second->First then 'Second' " diff --git a/tests/SpiffWorkflow/spiff/BaseTestCase.py b/tests/SpiffWorkflow/spiff/BaseTestCase.py index f1826a78d..5b8533f50 100644 --- a/tests/SpiffWorkflow/spiff/BaseTestCase.py +++ b/tests/SpiffWorkflow/spiff/BaseTestCase.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- import os -from copy import deepcopy from SpiffWorkflow.spiff.parser.process import SpiffBpmnParser, VALIDATOR from SpiffWorkflow.spiff.serializer.config import SPIFF_SPEC_CONFIG diff --git a/tests/SpiffWorkflow/spiff/CorrelationTest.py b/tests/SpiffWorkflow/spiff/CorrelationTest.py index 1b1a2be30..6589eb2b8 100644 --- a/tests/SpiffWorkflow/spiff/CorrelationTest.py +++ b/tests/SpiffWorkflow/spiff/CorrelationTest.py @@ -1,10 +1,3 @@ -import os -import sys -import unittest - -dirname = os.path.dirname(__file__) -sys.path.insert(0, os.path.join(dirname, '..', '..', '..')) - from SpiffWorkflow.bpmn.workflow import BpmnWorkflow from .BaseTestCase import BaseTestCase diff --git a/tests/SpiffWorkflow/spiff/MultiInstanceTaskTest.py b/tests/SpiffWorkflow/spiff/MultiInstanceTaskTest.py new file mode 100644 index 000000000..61e89e1fd --- /dev/null +++ b/tests/SpiffWorkflow/spiff/MultiInstanceTaskTest.py @@ -0,0 +1,29 @@ +from SpiffWorkflow.bpmn.workflow import BpmnWorkflow + +from .BaseTestCase import BaseTestCase + + +class MultiInstanceTaskTest(BaseTestCase): + + def testMultiInstanceTask(self): + spec, subprocesses = self.load_workflow_spec('spiff_multiinstance.bpmn', 'Process_1') + self.workflow = BpmnWorkflow(spec, subprocesses) + start = self.workflow.get_tasks_from_spec_name('Start')[0] + start.data = {'input_data': [1, 2, 3]} + self.workflow.do_engine_steps() + task = self.workflow.get_tasks_from_spec_name('any_task')[0] + self.workflow.do_engine_steps() + + self.save_restore() + + ready_tasks = self.workflow.get_ready_user_tasks() + for task in ready_tasks: + task.data['output_item'] = task.data['input_item'] * 2 + task.complete() + self.workflow.do_engine_steps() + + self.assertTrue(self.workflow.is_completed()) + self.assertDictEqual(self.workflow.data, { + 'input_data': [2, 3, 4], # Prescript adds 1 to input + 'output_data': [3, 5, 7], # Postscript subtracts 1 from output + }) diff --git a/tests/SpiffWorkflow/spiff/data/spiff_multiinstance.bpmn b/tests/SpiffWorkflow/spiff/data/spiff_multiinstance.bpmn new file mode 100644 index 000000000..f8b5fdbd8 --- /dev/null +++ b/tests/SpiffWorkflow/spiff/data/spiff_multiinstance.bpmn @@ -0,0 +1,49 @@ + + + + + Flow_1hjrex4 + + + + input_data = [ v + 1 for v in input_data ] + output_data = [ v - 1 for v in output_data ] + + Flow_1hjrex4 + Flow_1xndbxy + + input_data + output_data + + + + + + + Flow_1xndbxy + + + + + + + + + + + + + + + + + + + + + + + + + + From db442e1ee0f4096a21585455e0561f88009ac739 Mon Sep 17 00:00:00 2001 From: burnettk Date: Thu, 23 Feb 2023 10:49:54 -0500 Subject: [PATCH 36/41] Squashed 'spiffworkflow-backend/' changes from 031713a6..6cae736a 6cae736a Merge pull request #145 from sartography/data_size_script 241cb6ed Merge branch 'main' of github.com:sartography/spiff-arena 53e824ab set git user configs explicitly using the env vars w/ burnettk 741dab7e so we do not lose our minds when debugging on a server 8dd5d834 Merge branch 'main' of github.com:sartography/spiff-arena 44390824 show help text for textareas as well w/ burnettk 92042e9a why not dict, too d0b67bb8 Cleanup 4ffba533 Getting ./bin/pyl to pass d53d0c21 Provide info about keys in task data and python env 02db5acf Unfactor to fix size calculation/type hint issues 84fe64b0 Getting ./bin/pyl to pass 60a03f03 Adding python env size a929ef91 Add cumulative task data size to script 32bb223b remove start and end events from simple logs view 54fdfd46 copy env so we are doing additive stuff rather than completely rewriting it 833a4125 fix git bash script unbound error w/ burnettk 46c62b90 more git config updates w/ burnettk 621e13fb disable strict host checking for git commands w/ burnettk 182d657d fixed tests w/ burnettk 40db077e give access to download process data files if a user has access to start a process model w/ burnettk 9083fcae backend: create SSH key file when contents provided 90aad09e backend: use sensible lock filename for git 0065b98b backend: specify --rebase when using git pull 94e1e15c backend: fix use of SSH private key for git ops 55252831 Look in task data/script engine environment for data, not just workflow data. (#143) c5661f96 delint d2d1ee50 backend/git_service: accept webhook test requests 782650d7 backend/git_service: check repo URLs from webhook e76114c9 bump spiffworkflow hash 00d8eb55 put the env vars in the env section of the github action configs w/ burnettk 279e3042 added test for quickstart guide w/ burnettk 0e8ebc26 pyl 8732bd25 Merge remote-tracking branch 'origin/main' into feature/support_local_openid_in_cypress_tests 5b89d0cf use _GIT_SOURCE_BRANCH instead of _GIT_BRANCH 18917e62 fix unprefixed config f32d83de update configs for publish feature 6139b411 added some support for using the backend openid server for cypress tests w/ burnettk a2792e4d add new uses and delete ppg.ba.sme1 512bce0f the equal sign is not apart of the env var w/ burnettk 28b25fae updated terraform deployed env config name w/ burnettk 88fe9e66 more config updates w/ burnettk 6ad3224b cleaned up the default config file a bit f328b5db pyl 4ef72a9c fixed some env vars for ci 9a31aff0 pyl 2a642f38 Merge remote-tracking branch 'origin/main' into feature/update_configs_with_prefix 9f144f54 remove unused import ab6c45bc all tests pass w/ spiff lib upgrade, thanks for the help elizabeth 27870682 format dd0a642a updated remaining configs manually w/ burnettk d3153224 updated secret config names as well w/ burnettk 7160c702 updated configs to use the prefix using the script w/ burnettk e57476ac updated default user group var name for better prefix w/ burnettk 6d3ef2b8 save task data to spiff step details when copmleting a user task as well w/ burnettk jbirddog fde9ac7f append OPEN_ID to TENANT_SPECIFIC_FIELDS for clarification on what it is from w/ burnettk df34d786 do not remove the default user group when refreshing permissions w/ burnettk a80f7513 Merge branch 'main' of github.com:sartography/spiff-arena into main 7c63f409 The aud in a json web token can be a string or an array -- so also deal with the case that it is an array 76fd4c2d updates to user import scripts w/ burnettk f0067eea commit user if it has changed any attributes w/ burnettk 2f1cb4c0 fix for mypy on python 3.9 w/ burnettk b2db377d give some leeway to iat when validating auth w/ burnettk bce49095 add in debug logging when failing to login to help debug auth failures af2d9a66 Don't try to complete a ready task to move the process instance diagram to the next yellow. (#136) ee7d5b1e Merge pull request #137 from sartography/failing_test a1e5111f allow overriding keycloak url in add user script w/ burnettk d3b20221 updated add test users script to use realm admin w/ burnettk 390287bd The End Event has a spiff step 4e6bee21 added script to import users w/ burnettk ff8912f5 added api endpoint to allow logging in for the first time with an openid access_token w/ burnettk 7fab1f4f Merge pull request #135 from sartography/bug/len 73e4178d run_pyl 9c40e56e delete 15 users that are no longer needed 82c42a66 Merge remote-tracking branch 'origin/main' into bug/len 057102c1 commit before removing users fbee1e31 This should fix the len issue - though there may be better ways to fix this. This reverts commit 52b496d1058a630ee60c50c3e8acc72b2df748dc. e48c3188 Revert "more finally for better len" b398f53a more finally for better len added a fixme for raising errors fixed up an error message 3d22455e fix employee id 9eb0c08d Update Spiffworkflow so we have the better error messages on service tasks. 54e17133 don't default to a broken environment. 44acb13d add five test users, rename peopleops users, delete two 27bbacaf Remove version from docker-compose, as this is causing issues for people still using docker-compose v2. 74984c8e turn off profiling for now to see if that is what is causing segfaults 733fe927 Save logs in finally (#134) 37f728a7 link to the spiff step from a task on the frontend and use the correct db in ci 3c120843 pyl w/ burnettk af10992a call activities are also working w/ burnettk d0aa6b1c tasks and subprocesses can are setting the task states properly now when getting task data w/ burnettk jbirddog 4791bda5 pyl w/ burnettk ffa4fd78 Merge branch 'save_step_data' of github.com:sartography/spiff-arena into save_step_data 9e3a897b Fix bug where deletes from the environment were not removed from the task data as well 7eebf361 Merge remote-tracking branch 'origin/main' into save_step_data b4f22984 Merge pull request #132 from sartography/feature/no_more_current_user db3d4703 updated controller to use spiff step details to find correct task data to show w/ burnettk b3a70d42 run_pyl fca00361 remove the "current_user" from being added to the task_data. 747f91d1 Merge remote-tracking branch 'origin/main' into save_step_data ac02e0a9 Merge remote-tracking branch 'origin/main' into save_step_data cce05cab pyl dc250235 Merge pull request #131 from sartography/feature/improved_service_task_errors 4d9a7a6a If you have an instance/config.py to override local development it would also override testing. c06db317 Use a mock when making external calls in tests. d6654e82 Merge remote-tracking branch 'origin/main' into feature/improved_service_task_errors 6e4b191c Merge branch 'main' of github.com:sartography/spiff-arena 0fd982a4 catch up with environment change 81a7cdc9 added additional columns to spiff_step_details w/ burnettk jbirddog 805b86ec fixing some missing types 8644561b run_pyl 72deffd8 Assure that when something goes wrong calling a service task that we get as much good information about the problem as possible. 687125bd Merge remote-tracking branch 'origin/main' into save_step_data 9c8ca3aa enable faulthandler to hopefully see seg faults in the logs w/ burnettk jbirddog a9651211 Merge branch 'main' into save_step_data bc556729 remove dup 10fa5edf add users d7f52641 Merge pull request #114 from sartography/frontend/use-api-subpath 35efb091 allow setting configs for the frontend through env vars w/ burnettk 7552408a allow configuring gunicorn configs in boot_server_in_docker w/ burnettk 1007e8c7 sentences need spaces between them 1b7fec4a renamed development env to local_development and testing to unit_testing w/ burnettk 02750228 set up qa2 to only do path based routing w/ burnettk ee3cb621 added backend url to qa2 configs fab0a6bd added qa2 configs to use keycloak on qa1 to test different domains w/ burnettk f7743ea4 Merge pull request #128 from sartography/feature/bug_fixes 384d65f6 Update tasks_controller.py 7f0c0926 update get_token af5a4c50 pass tenant attributes when creating a user w/ burnettk 2cf6f1a5 pyl w/ burnettk b7bdae94 Merge remote-tracking branch 'origin/main' into feature/tenant-specific-fields-from-openid 007eecdc added bambooid to status users w/ burnettk 3b0e3ff6 POC for saving some data about each step 98490b69 allow added custom attributes to users when adding to keycloak w/ burnettk 68358519 Backend do_engine_steps performance improvements (#129) 2a2855e0 use our json encoder to dump the user for get_current_user script w/ burnettk 706bb570 Use the same markdown library for displaying as for editing - could enable a security run_pyl 7aebec9d When catching non-jinja errors from Jinja, raise a good error message, and make a best effort at tracking down the line number and error line if possible. b4a31562 move towards returning dict in get_current_user 19ccca40 Merge remote-tracking branch 'origin/main' into feature/tenant-specific-fields-from-openid 257de512 add test users ecc70795 run_pyl 3eb0fd76 When searching for human tasks to determine if the current user can complete it, filter on the "completed" flag. ad4fead4 Back to inserting every log 12c3a2b8 hoping to fix tests on windows d8ba46b6 grab bamboo_id from keycloak e5a56f6e lint f1c61581 if there are tenant specific fields in the config, transfer them from openid token to db 35637ba0 Merge branch 'main' of github.com:sartography/spiff-arena into main 86b248fa Fix that dreadful unknown "KeyError" exception that was cropping up. Adding a bit of detail to the spiffworkflow exceptions when a duplicate process model is found. Disable the submit button on tasks after you click submit (avoid the double click and give users a better experience) 6fc2f2b2 Merge pull request #125 from sartography/feature/dynamically-hide-fields-w-task-data 9de6e0b3 refactor some stuff in task_show to separate functions f2a12c5c show that hiding nested fields works as well d7fd92e1 make form schema and form ui schema both dicts, add support for hiding fields based on task data 80649382 run_pyl 5a859f16 Merge branch 'main' into feature/more_better_errors 2d4f9d45 add more users, and try to prevent sentry notification again 83b9c901 remove service accounts, formalize j, add madhurya 698b3af8 make test_user_lists more complete and correct a163d6f7 clean up sentry notification and avoid logger.exception when we do not want sentry 0fced76d couple last serializer updates b17142bf import EventBasedGatewayConverter from correct package 5b7805d0 try to improve exception handling by avoiding raising ApiError from services e9913d83 simplify spiff integration post serializer update, w/ elizabeth and jon 9baf0cb2 Quick fix for url building 4641b523 File download from workflow data (#122) 30a73e2a Allow for different Python Environments when executing scripts within SpiffWorkflow (#121) 650b91ed add keycloak users 6d18bd23 bulk insert logs for performance improvement c50744a1 there is no need to ever sentry_sdk.start_transaction because the flask integration does that 1368d71c get some more insight into connector proxy timings 7ffcded9 avoid poetry installing deps when we have them cached if they do not change 5d50ee8e more spans to track performance a23a0700 more sentry performance tracing 8a98e8d9 folks who can start instances can also view their logs 17fb81bc shuffle around Dockerfile to allow to work for background container d9bcbd09 Merge pull request #117 from sartography/feature/authorization c586e0ea allow overriding git related configs w/ env var and log permissions stuff on boot f5ee3ec8 Merge branch 'main' into feature/more_better_errors 063ebda6 Merge pull request #115 from sartography/backend/improve-dockerfile ba6d4c5f Fix typing issue. b0a05adc Use the id_token, not the auth_token from the open id server for authentication with the front end. The auth_token should be kept safe, and not guranteeded to be a json token. b9eb5dd8 add four new status users to spiff realm 553c93be backend: avoid redundant steps in Dockerfile cf2e8975 removed old pin to spiffworkflow w/ burnettk 5970b1e3 tests are passing now w/ burnettk a39aca6a some initial updates w/ burnettk 6fda0c5c Allow set to be called from scripts a6482760 update lock file in backend and arena, though that one needs pruning 5b2046ab run_pyl 5328a2d4 Workflow Data Exceptions were not getting processed, we now catch the WorkflowDataException through the generic top level SpiffWorkflowException. 9f98cfee updated prefix for background instances w/ burnettk acd26c04 Merge pull request #110 from sartography/feature/jinja_errors 864ae116 add keycloak users f80836e7 pyl 71e20c9f set the correct type for task since SpiffTask and a backend task are not the same 26c791f9 increased the task data size 79dadcaa added pylint back to lock file 35b0871c Merge remote-tracking branch 'origin/main' into feature/jinja_errors 1dbac99a run_pyl had various recommendations that I find a bit of a pain in the butt, but that I did anyway. b30081ab Merge pull request #109 from sartography/feature/upgrade_bandit efb8fd0b removed debug print statements 58679f60 ensure we are passing the primary file name to the delete file test 9943cbbb fixed typo w/ burnettk 1fe63808 added some debug statements for ci w/ burnettk d84942f0 upgraded bandit and flake8 w/ burnettk 72f599cb Merge remote-tracking branch 'origin/main' into feature/jinja_errors c0530539 allow removing users from groups when refreshing permissions w/ burnettk 106500cf Added useMemo to error context No longer clear errors in the task bar, as that will constantly remove them as soon as they are shown. 08c3106c Merge branch 'main' of github.com:sartography/spiff-arena 957e0373 when changing the primary file name also change the primary process when updating a process model from the api w/ burnettk b560b364 Making sure we create informative messages when encountering jinja2 syntax errors. 51c325da delete legacy flask-rendered html pages from initial prototype, since backend is now API-only 59ebcbb4 added the process model identifier for the diagram if it is not the top level w/ burnettk a02a132e Merge pull request #107 from sartography/feature/metadata_on_instance_show b22e8828 do not allow deleting primary bpmn file and do not allow instantiating models without a primary bpmn file w/ burnettk 002df3f9 show metadata on instance show page but for some reason it reorders elements w/ burnettk 81c3cfe1 removed uniqueness constraint from human task so we can loopback to a previous task with a gateway w/ burnettk 73cbef31 ensure order of permissions in tests d5949b86 document future enhancement c8bc2049 strip off newlines and spaces when importing secrets and pinning spiffworkflow to working version until we can debug issues with new one w/ burnettk bb99d942 added locking system for process instances so hopefully background jobs will not take instances currently being run by the user w/ burnettk a4e60a36 added uniqueness constraint to spiff step details w/ burnettk 5fd7197c add sum and format 53d99f7d expanded functionality of the form builder f08ff45b Revert "allow updating models on staging for a bit" f88d3250 Revert "commit on save yes for now" 6675c407 qa1 10180043 since accepting the github host entry programatically is no more secure 1517a3ee commit on save yes for now 5f1af4a6 allow updating models on staging for a bit 27fbd93d allow getting the GIT SSH key from an app config so we can set it in the secrets file w/ burnettk 9fa2f982 allow specifying an ssh key for git instead of a username and password w/ burnettk 09337070 updated admin user on sartography realm w/ burnettk 17124319 allow passing a realm name into start keycloak and added admin user to sartography realm 7d9600f4 find the top level process to find the task form when using subprocesses in called activities w/ burnettk danfunk 0bf13094 pyl w/ burnettk 97268226 Merge branch 'main' into feature/improved_errors c1403a9e ensure we have something in the logs w/ burnettk cdaf59b8 pyl w/ burnettk 55468b67 added configs for sartography env w/ burnettk 205dd4a5 pre-commit-in-ci bd1058fe updating spiffworkflow version, and fixing the run_pyl (by removing the corft I stuck in earlier) ecbe1948 Merges 5da88709 Lots of adjustments from running pyl Main change is in the ErrorDisplay.tsx to assure all error information is provided. and index.css to make it "pretty" ab1d5c22 Removing dependency on flask-bpmn and taking it out of SpiffArena Slightly updating the APIError code for recent updates to SpiffWorkflow's error refactoring. git-subtree-dir: spiffworkflow-backend git-subtree-split: 6cae736acd232199447a44f7ff2a8dc4c7779631 --- .flake8 | 16 +- .github/workflows/tests.yml | 4 +- Dockerfile | 52 +- bin/boot_server_in_docker | 38 +- bin/build_and_run_with_docker_compose | 4 +- bin/deploy | 8 +- bin/find_sample_process_models | 16 +- bin/get_bpmn_json_for_process_instance | 4 +- bin/get_token | 39 +- bin/git_commit_bpmn_models_repo | 36 +- bin/import_tickets_for_command_line.py | 3 +- bin/import_tickets_for_script_task.py | 2 +- bin/login_with_users | 40 + bin/recreate_db | 36 +- bin/run_server_locally | 16 +- bin/save_to_secrets_from_file | 33 + bin/wait_for_server_to_be_up | 9 +- conftest.py | 6 +- docker-compose.yml | 22 +- keycloak/bin/add_test_users_to_keycloak | 82 +- keycloak/bin/export_keycloak_realms | 3 + keycloak/bin/start_keycloak | 15 +- keycloak/bin/wait_for_keycloak | 11 +- keycloak/realm_exports/sartography-realm.json | 2552 +++++++++++++ .../realm_exports/spiffworkflow-realm.json | 1353 +++++-- keycloak/test_user_lists/sartography | 15 + keycloak/test_user_lists/status | 62 +- .../{907bcf0c3d75_.py => 2ec4222f0012_.py} | 14 +- migrations/versions/63fc8d693b9f_.py | 34 + migrations/versions/ca9b79dde5cc_.py | 32 + migrations/versions/e05ca5cdc312_.py | 38 + noxfile.py | 2 +- poetry.lock | 185 +- pyproject.toml | 10 +- src/.coverage.jason-Gazelle.473795.719220 | Bin 77824 -> 0 bytes src/.coverage.jason-Gazelle.475245.497833 | Bin 77824 -> 0 bytes src/.coverage.jason-Gazelle.476451.578823 | Bin 77824 -> 0 bytes src/spiffworkflow_backend/__init__.py | 71 +- src/spiffworkflow_backend/api.yml | 59 + src/spiffworkflow_backend/config/__init__.py | 61 +- src/spiffworkflow_backend/config/default.py | 131 +- src/spiffworkflow_backend/config/demo.py | 11 +- src/spiffworkflow_backend/config/dev.py | 13 +- .../config/development.py | 19 - .../config/local_development.py | 23 + .../config/permissions/example.yml | 28 +- ...{development.yml => local_development.yml} | 0 .../{testing.yml => unit_testing.yml} | 0 src/spiffworkflow_backend/config/qa1.py | 13 +- src/spiffworkflow_backend/config/qa2.py | 14 + .../config/sartography.py | 15 + src/spiffworkflow_backend/config/staging.py | 10 +- .../config/terraform_deployed_environment.py | 30 +- .../config/{testing.py => unit_testing.py} | 6 +- .../exceptions/api_error.py | 261 ++ .../helpers/db_helper.py | 3 +- .../load_database_models.py | 2 +- src/spiffworkflow_backend/models/db.py | 85 + src/spiffworkflow_backend/models/group.py | 9 +- .../models/human_task.py | 7 +- .../models/human_task_user.py | 7 +- .../models/message_correlation.py | 4 +- .../message_correlation_message_instance.py | 4 +- .../models/message_correlation_property.py | 4 +- .../models/message_instance.py | 4 +- .../models/message_model.py | 4 +- .../message_triggerable_process_model.py | 4 +- .../models/permission_assignment.py | 4 +- .../models/permission_target.py | 5 +- src/spiffworkflow_backend/models/principal.py | 4 +- .../models/process_instance.py | 23 +- .../models/process_instance_metadata.py | 4 +- .../models/process_instance_report.py | 4 +- .../models/refresh_token.py | 5 +- .../models/secret_model.py | 4 +- .../models/spec_reference.py | 5 +- .../models/spiff_logging.py | 4 +- .../models/spiff_step_details.py | 30 +- src/spiffworkflow_backend/models/task.py | 14 +- src/spiffworkflow_backend/models/user.py | 7 +- .../models/user_group_assignment.py | 4 +- .../models/user_group_assignment_waiting.py | 4 +- .../routes/admin_blueprint/__init__.py | 1 - .../routes/admin_blueprint/admin_blueprint.py | 187 - .../routes/admin_blueprint/static/app.js | 26 - .../admin_blueprint/static/package-lock.json | 3172 ----------------- .../admin_blueprint/static/package.json | 18 - .../routes/admin_blueprint/static/style.css | 2 - .../admin_blueprint/templates/layout.html | 23 - .../templates/process_group_list.html | 18 - .../templates/process_group_show.html | 25 - .../templates/process_model_edit.html | 167 - .../templates/process_model_show.html | 159 - .../routes/messages_controller.py | 2 +- .../openid_blueprint/templates/login.html | 8 +- .../routes/process_api_blueprint.py | 71 +- .../routes/process_groups_controller.py | 2 +- .../routes/process_instances_controller.py | 133 +- .../routes/process_models_controller.py | 45 +- .../routes/script_unit_tests_controller.py | 2 +- .../routes/service_tasks_controller.py | 6 +- .../routes/tasks_controller.py | 269 +- src/spiffworkflow_backend/routes/user.py | 48 +- .../routes/user_blueprint.py | 4 +- .../routes/users_controller.py | 8 +- .../delete_process_instances_with_criteria.py | 2 +- .../scripts/get_current_user.py | 10 +- .../scripts/get_data_sizes.py | 46 + .../scripts/get_frontend_url.py | 2 +- .../scripts/get_localtime.py | 2 +- .../scripts/markdown_file_download_link.py | 53 + .../scripts/save_process_instance_metadata.py | 3 +- src/spiffworkflow_backend/scripts/script.py | 3 +- .../services/acceptance_test_fixtures.py | 2 +- .../services/authentication_service.py | 77 +- .../services/authorization_service.py | 163 +- .../services/data_setup_service.py | 2 +- .../services/error_handling_service.py | 6 +- .../services/file_system_service.py | 6 +- .../services/git_service.py | 113 +- .../services/group_service.py | 3 +- .../services/logging_service.py | 9 +- .../services/message_service.py | 2 +- .../services/process_instance_processor.py | 655 +++- .../process_instance_report_service.py | 4 +- .../services/process_instance_service.py | 45 +- .../services/process_model_service.py | 8 +- .../services/script_unit_test_runner.py | 8 +- .../services/secret_service.py | 5 +- .../services/service_task_service.py | 106 +- .../services/spec_file_service.py | 4 +- .../services/user_service.py | 10 +- .../color_question.json | 12 + .../dynamic_enums_ask_for_color.bpmn | 4 +- tests/data/error/instructions_error.bpmn | 45 + .../loopback_to_manual_task/loopback.bpmn | 65 + .../lanes_with_owner_dict.bpmn | 3 +- .../process_navigation.bpmn | 2 +- .../simple_form_with_error/simple_form.json | 18 + .../simple_form_ui.json | 11 + .../simple_form_with_error.bpmn | 63 + tests/data/spiff_example/multiinstance.bpmn | 4 +- .../timer_intermediate_catch_event.bpmn | 2 +- .../helpers/base_test.py | 4 +- .../helpers/test_data.py | 2 +- .../integration/test_for_good_errors.py | 103 + .../integration/test_process_api.py | 60 +- .../integration/test_secret_service.py | 2 +- .../scripts/test_get_all_permissions.py | 18 +- .../scripts/test_get_current_user.py | 46 + .../scripts/test_get_group_members.py | 2 +- .../scripts/test_get_localtime.py | 3 +- .../scripts/test_refresh_permissions.py | 2 +- .../unit/test_authorization_service.py | 179 +- .../unit/test_environment_var_script.py | 2 +- .../unit/test_message_instance.py | 2 +- .../unit/test_permission_target.py | 2 +- .../unit/test_permissions.py | 2 +- .../unit/test_process_instance_processor.py | 86 +- .../test_process_instance_report_service.py | 2 +- .../unit/test_process_instance_service.py | 20 +- .../unit/test_process_model.py | 2 +- .../unit/test_restricted_script_engine.py | 2 +- .../unit/test_service_task_delegate.py | 20 + .../unit/test_spec_file_service.py | 2 +- .../unit/test_spiff_logging.py | 2 +- 166 files changed, 7296 insertions(+), 5058 deletions(-) create mode 100755 bin/login_with_users create mode 100644 bin/save_to_secrets_from_file create mode 100644 keycloak/realm_exports/sartography-realm.json create mode 100644 keycloak/test_user_lists/sartography rename migrations/versions/{907bcf0c3d75_.py => 2ec4222f0012_.py} (98%) create mode 100644 migrations/versions/63fc8d693b9f_.py create mode 100644 migrations/versions/ca9b79dde5cc_.py create mode 100644 migrations/versions/e05ca5cdc312_.py delete mode 100644 src/.coverage.jason-Gazelle.473795.719220 delete mode 100644 src/.coverage.jason-Gazelle.475245.497833 delete mode 100644 src/.coverage.jason-Gazelle.476451.578823 delete mode 100644 src/spiffworkflow_backend/config/development.py create mode 100644 src/spiffworkflow_backend/config/local_development.py rename src/spiffworkflow_backend/config/permissions/{development.yml => local_development.yml} (100%) rename src/spiffworkflow_backend/config/permissions/{testing.yml => unit_testing.yml} (100%) create mode 100644 src/spiffworkflow_backend/config/qa2.py create mode 100644 src/spiffworkflow_backend/config/sartography.py rename src/spiffworkflow_backend/config/{testing.py => unit_testing.py} (77%) create mode 100644 src/spiffworkflow_backend/exceptions/api_error.py create mode 100644 src/spiffworkflow_backend/models/db.py delete mode 100644 src/spiffworkflow_backend/routes/admin_blueprint/__init__.py delete mode 100644 src/spiffworkflow_backend/routes/admin_blueprint/admin_blueprint.py delete mode 100644 src/spiffworkflow_backend/routes/admin_blueprint/static/app.js delete mode 100644 src/spiffworkflow_backend/routes/admin_blueprint/static/package-lock.json delete mode 100644 src/spiffworkflow_backend/routes/admin_blueprint/static/package.json delete mode 100644 src/spiffworkflow_backend/routes/admin_blueprint/static/style.css delete mode 100644 src/spiffworkflow_backend/routes/admin_blueprint/templates/layout.html delete mode 100644 src/spiffworkflow_backend/routes/admin_blueprint/templates/process_group_list.html delete mode 100644 src/spiffworkflow_backend/routes/admin_blueprint/templates/process_group_show.html delete mode 100644 src/spiffworkflow_backend/routes/admin_blueprint/templates/process_model_edit.html delete mode 100644 src/spiffworkflow_backend/routes/admin_blueprint/templates/process_model_show.html create mode 100644 src/spiffworkflow_backend/scripts/get_data_sizes.py create mode 100644 src/spiffworkflow_backend/scripts/markdown_file_download_link.py create mode 100644 tests/data/error/instructions_error.bpmn create mode 100644 tests/data/loopback_to_manual_task/loopback.bpmn create mode 100644 tests/data/simple_form_with_error/simple_form.json create mode 100644 tests/data/simple_form_with_error/simple_form_ui.json create mode 100644 tests/data/simple_form_with_error/simple_form_with_error.bpmn create mode 100644 tests/spiffworkflow_backend/integration/test_for_good_errors.py create mode 100644 tests/spiffworkflow_backend/scripts/test_get_current_user.py diff --git a/.flake8 b/.flake8 index 481ae8d32..456b44229 100644 --- a/.flake8 +++ b/.flake8 @@ -8,11 +8,19 @@ rst-roles = class,const,func,meth,mod,ref rst-directives = deprecated per-file-ignores = + # More specific globs seem to overwrite the more generic ones so we have + # to split them out by directory + # So if you have a rule like: + # tests/*: D102,D103 + # and a rule like: + # tests/test_hey.py: D102 + # THEN, test_hey.py will NOT be excluding D103 + # asserts are ok in tests - tests/*:S101 + tests/*:S101,D102,D103 # prefer naming functions descriptively rather than forcing comments - *:D103 + src/*:D102,D103 bin/keycloak_test_server.py:B950,D conftest.py:S105 @@ -24,11 +32,11 @@ per-file-ignores = # the exclude=./migrations option doesn't seem to work with pre-commit # migrations are autogenerated from "flask db migration" so ignore them migrations/*:D - src/spiffworkflow_backend/config/testing.py:S105 + src/spiffworkflow_backend/config/unit_testing.py:S105 src/spiffworkflow_backend/load_database_models.py:F401 # this file overwrites methods from the logging library so we can't change them # and ignore long comment line src/spiffworkflow_backend/services/logging_service.py:N802,B950 - tests/spiffworkflow_backend/integration/test_process_api.py:S607,S101,D103,S605 + tests/spiffworkflow_backend/integration/test_process_api.py:S607,S101,S605,D102,D103,D101 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f1db9198c..af6620468 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -142,12 +142,12 @@ jobs: host port: 3306 container port: 3306 mysql version: "8.0" - mysql database: "spiffworkflow_backend_testing" + mysql database: "spiffworkflow_backend_unit_testing" mysql root password: password if: matrix.database == 'mysql' - name: Setup Postgres - run: docker run --name postgres-spiff -p 5432:5432 -e POSTGRES_PASSWORD=spiffworkflow_backend -e POSTGRES_USER=spiffworkflow_backend -e POSTGRES_DB=spiffworkflow_backend_testing -d postgres + run: docker run --name postgres-spiff -p 5432:5432 -e POSTGRES_PASSWORD=spiffworkflow_backend -e POSTGRES_USER=spiffworkflow_backend -e POSTGRES_DB=spiffworkflow_backend_unit_testing -d postgres if: matrix.database == 'postgres' - name: Run Nox diff --git a/Dockerfile b/Dockerfile index e2d89bebd..ef915bde3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,28 +1,44 @@ -FROM ghcr.io/sartography/python:3.11 +# Base image to share ENV vars that activate VENV. +FROM ghcr.io/sartography/python:3.11 AS base + +ENV VIRTUAL_ENV=/app/venv +RUN python3 -m venv $VIRTUAL_ENV +ENV PATH="$VIRTUAL_ENV/bin:$PATH" + +WORKDIR /app + +# base plus packages needed for deployment. Could just install these in final, but then we can't cache as much. +# vim is just for debugging +FROM base AS deployment + +RUN apt-get update \ + && apt-get clean -y \ + && apt-get install -y -q curl git-core gunicorn3 default-mysql-client vim \ + && rm -rf /var/lib/apt/lists/* + +# Setup image for installing Python dependencies. +FROM base AS setup RUN pip install poetry RUN useradd _gunicorn --no-create-home --user-group -RUN apt-get update && \ - apt-get install -y -q \ - gcc libssl-dev \ - curl git-core libpq-dev \ - gunicorn3 default-mysql-client +RUN apt-get update \ + && apt-get install -y -q gcc libssl-dev libpq-dev -WORKDIR /app +# poetry install takes a long time and can be cached if dependencies don't change, +# so that's why we tolerate running it twice. COPY pyproject.toml poetry.lock /app/ RUN poetry install --without dev -RUN set -xe \ - && apt-get remove -y gcc python3-dev libssl-dev \ - && apt-get autoremove -y \ - && apt-get clean -y \ - && rm -rf /var/lib/apt/lists/* - -COPY . /app/ - -# run poetry install again AFTER copying the app into the image -# otherwise it does not know what the main app module is +COPY . /app RUN poetry install --without dev -CMD ./bin/boot_server_in_docker +# Final image without setup dependencies. +FROM deployment AS final + +LABEL source="https://github.com/sartography/spiff-arena" +LABEL description="Software development platform for building, running, and monitoring executable diagrams" + +COPY --from=setup /app /app + +CMD ["./bin/boot_server_in_docker"] diff --git a/bin/boot_server_in_docker b/bin/boot_server_in_docker index 00c6b5d96..fb425af5c 100755 --- a/bin/boot_server_in_docker +++ b/bin/boot_server_in_docker @@ -10,12 +10,12 @@ set -o errtrace -o errexit -o nounset -o pipefail # run migrations export FLASK_APP=/app/src/spiffworkflow_backend -if [[ "${WAIT_FOR_DB_TO_BE_READY:-}" == "true" ]]; then +if [[ "${SPIFFWORKFLOW_BACKEND_WAIT_FOR_DB_TO_BE_READY:-}" == "true" ]]; then echo 'Waiting for db to be ready...' poetry run python ./bin/wait_for_db_to_be_ready.py fi -if [[ "${DOWNGRADE_DB:-}" == "true" ]]; then +if [[ "${SPIFFWORKFLOW_BACKEND_DOWNGRADE_DB:-}" == "true" ]]; then echo 'Downgrading database...' poetry run flask db downgrade fi @@ -25,6 +25,14 @@ if [[ "${SPIFFWORKFLOW_BACKEND_UPGRADE_DB:-}" == "true" ]]; then poetry run flask db upgrade fi +if [[ -z "${GUNICORN_LOG_LEVEL:-}" ]]; then + GUNICORN_LOG_LEVEL=debug +fi + +if [[ -z "${GUNICORN_TIMEOUT_SECONDS:-}" ]]; then + GUNICORN_TIMEOUT_SECONDS=90 +fi + port="${SPIFFWORKFLOW_BACKEND_PORT:-}" if [[ -z "$port" ]]; then port=7000 @@ -32,8 +40,8 @@ fi additional_args="" -if [[ "${APPLICATION_ROOT:-}" != "/" ]]; then - additional_args="${additional_args} -e SCRIPT_NAME=${APPLICATION_ROOT}" +if [[ "${SPIFFWORKFLOW_BACKEND_APPLICATION_ROOT:-}" != "/" ]]; then + additional_args="${additional_args} -e SCRIPT_NAME=${SPIFFWORKFLOW_BACKEND_APPLICATION_ROOT}" fi # HACK: if loading fixtures for acceptance tests when we do not need multiple workers @@ -47,7 +55,25 @@ if [[ "${SPIFFWORKFLOW_BACKEND_RUN_DATA_SETUP:-}" != "false" ]]; then SPIFFWORKFLOW_BACKEND_FAIL_ON_INVALID_PROCESS_MODELS=false poetry run python bin/save_all_bpmn.py fi -export IS_GUNICORN="true" +if [[ -n "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY:-}" ]]; then + if [[ -z "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH:-}" ]]; then + export SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH=$(mktemp /tmp/ssh_private_key.XXXXXX) + fi + chmod 600 "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH}" + echo "${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY}" >"${SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH}" +fi +# Assure that the the Process Models Directory is initialized as a git repo +git init "${SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR}" +git config --global --add safe.directory "${SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR}" + +export IS_GUNICORN="true" # THIS MUST BE THE LAST COMMAND! -exec poetry run gunicorn ${additional_args} --bind "0.0.0.0:$port" --workers="$workers" --limit-request-line 8192 --timeout 90 --capture-output --access-logfile '-' --log-level debug wsgi:app +exec poetry run gunicorn ${additional_args} \ + --bind "0.0.0.0:$port" \ + --workers="$workers" \ + --limit-request-line 8192 \ + --timeout "$GUNICORN_TIMEOUT_SECONDS" \ + --capture-output \ + --access-logfile '-' \ + --log-level "$GUNICORN_LOG_LEVEL" wsgi:app diff --git a/bin/build_and_run_with_docker_compose b/bin/build_and_run_with_docker_compose index c986e3941..58fd61f04 100755 --- a/bin/build_and_run_with_docker_compose +++ b/bin/build_and_run_with_docker_compose @@ -7,8 +7,8 @@ function error_handler() { trap 'error_handler ${LINENO} $?' ERR set -o errtrace -o errexit -o nounset -o pipefail -BPMN_SPEC_ABSOLUTE_DIR=$(./bin/find_sample_process_models) -export BPMN_SPEC_ABSOLUTE_DIR +SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR=$(./bin/find_sample_process_models) +export SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR if [[ -z "${SPIFFWORKFLOW_BACKEND_DOCKER_COMPOSE_PROFILE:-}" ]]; then export SPIFFWORKFLOW_BACKEND_DOCKER_COMPOSE_PROFILE=run diff --git a/bin/deploy b/bin/deploy index 466bb6d14..ebfd9a553 100755 --- a/bin/deploy +++ b/bin/deploy @@ -31,16 +31,16 @@ if [[ -z "${SPIFFWORKFLOW_BACKEND_DOCKER_COMPOSE_PROFILE:-}" ]]; then export SPIFFWORKFLOW_BACKEND_DOCKER_COMPOSE_PROFILE=run fi -if [[ -z "${SPIFFWORKFLOW_FRONTEND_URL:-}" ]]; then - export SPIFFWORKFLOW_FRONTEND_URL='http://167.172.242.138:7001' +if [[ -z "${SPIFFWORKFLOW_BACKEND_URL_FOR_FRONTEND:-}" ]]; then + export SPIFFWORKFLOW_BACKEND_URL_FOR_FRONTEND='http://167.172.242.138:7001' fi if [[ -z "${SPIFFWORKFLOW_BACKEND_URL:-}" ]]; then export SPIFFWORKFLOW_BACKEND_URL='http://167.172.242.138:7000' fi -if [[ -z "${OPEN_ID_SERVER_URL:-}" ]]; then - export OPEN_ID_SERVER_URL='http://167.172.242.138:7002' +if [[ -z "${SPIFFWORKFLOW_BACKEND_OPEN_ID_SERVER_URL:-}" ]]; then + export SPIFFWORKFLOW_BACKEND_OPEN_ID_SERVER_URL='http://167.172.242.138:7002' fi git pull diff --git a/bin/find_sample_process_models b/bin/find_sample_process_models index 525996399..ead42ca0b 100755 --- a/bin/find_sample_process_models +++ b/bin/find_sample_process_models @@ -7,19 +7,19 @@ function error_handler() { trap 'error_handler ${LINENO} $?' ERR set -o errtrace -o errexit -o nounset -o pipefail -if [[ -z "${BPMN_SPEC_ABSOLUTE_DIR:-}" ]]; then +if [[ -z "${SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR:-}" ]]; then script_dir="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" - BPMN_SPEC_ABSOLUTE_DIR="${script_dir}/../../../sample-process-models" - if [[ ! -d "$BPMN_SPEC_ABSOLUTE_DIR" ]]; then - BPMN_SPEC_ABSOLUTE_DIR="${script_dir}/../../sample-process-models" - if [[ ! -d "$BPMN_SPEC_ABSOLUTE_DIR" ]]; then - >&2 echo "ERROR: Could not find a location for the sample processes. Last tried: $BPMN_SPEC_ABSOLUTE_DIR" + SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR="${script_dir}/../../../sample-process-models" + if [[ ! -d "$SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR" ]]; then + SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR="${script_dir}/../../sample-process-models" + if [[ ! -d "$SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR" ]]; then + >&2 echo "ERROR: Could not find a location for the sample processes. Last tried: $SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR" exit 1 fi fi - pushd "$BPMN_SPEC_ABSOLUTE_DIR" >/dev/null 2>&1 + pushd "$SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR" >/dev/null 2>&1 if [[ "$(git rev-parse --abbrev-ref HEAD)" == "main" ]]; then >&2 echo "ERROR: please do not use the main branch of sample-process-models. use dev" exit 1 @@ -27,4 +27,4 @@ if [[ -z "${BPMN_SPEC_ABSOLUTE_DIR:-}" ]]; then popd >/dev/null 2>&1 fi -realpath "$BPMN_SPEC_ABSOLUTE_DIR" +realpath "$SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR" diff --git a/bin/get_bpmn_json_for_process_instance b/bin/get_bpmn_json_for_process_instance index dbce01ecc..d4e3d8ed0 100644 --- a/bin/get_bpmn_json_for_process_instance +++ b/bin/get_bpmn_json_for_process_instance @@ -8,7 +8,9 @@ from spiffworkflow_backend.models.process_instance import ProcessInstanceModel def main(process_instance_id: str): """Main.""" - os.environ["SPIFFWORKFLOW_BACKEND_ENV"] = "development" + os.environ["SPIFFWORKFLOW_BACKEND_ENV"] = "local_development" + if os.environ.get("SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR") is None: + os.environ["SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR"] = "hey" flask_env_key = "FLASK_SESSION_SECRET_KEY" os.environ[flask_env_key] = "whatevs" app = create_app() diff --git a/bin/get_token b/bin/get_token index 4e6aca021..b5e768208 100755 --- a/bin/get_token +++ b/bin/get_token @@ -20,28 +20,35 @@ set -o errtrace -o errexit -o nounset -o pipefail # ./bin/get_token repeat_form_user_1 repeat_form_user_1 # actually has permissions to the resource in this script # ./bin/get_token ciadmin1 ciadmin1 '%2Fprocess-models' -# 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 -REALM_NAME=spiffworkflow +if [[ -z "${KEYCLOAK_BASE_URL:-}" ]]; then + # KEYCLOAK_BASE_URL=http://localhost:7002 + KEYCLOAK_BASE_URL=https://keycloak.dev.spiffworkflow.org +fi +if [[ -z "${BACKEND_BASE_URL:-}" ]]; then + # BACKEND_BASE_URL=http://localhost:7000 + BACKEND_BASE_URL=https://api.dev.spiffworkflow.org +fi +if [[ -z "${BACKEND_CLIENT_ID:-}" ]]; then + export BACKEND_CLIENT_ID=spiffworkflow-backend +fi +if [[ -z "${BACKEND_CLIENT_SECRET:-}" ]]; then + export BACKEND_CLIENT_SECRET="JXeQExm0JhQPLumgHtIIqf52bDalHz0q" # noqa: S105 +fi USERNAME=${1-fin} PASSWORD=${2-fin} +REALM_NAME=${3-spiffworkflow} -FRONTEND_CLIENT_ID=spiffworkflow-frontend -BACKEND_CLIENT_ID=spiffworkflow-backend -BACKEND_CLIENT_SECRET="JXeQExm0JhQPLumgHtIIqf52bDalHz0q" # noqa: S105 SECURE=false BACKEND_BASIC_AUTH=$(echo -n "${BACKEND_CLIENT_ID}:${BACKEND_CLIENT_SECRET}" | base64) KEYCLOAK_URL=$KEYCLOAK_BASE_URL/realms/$REALM_NAME/protocol/openid-connect/token -echo "Using Keycloak: $KEYCLOAK_URL" -echo "realm: $REALM_NAME" -echo "client-id: $FRONTEND_CLIENT_ID" -echo "username: $USERNAME" -echo "password: $PASSWORD" -echo "secure: $SECURE" +>&2 echo "Using Keycloak: $KEYCLOAK_URL" +>&2 echo "realm: $REALM_NAME" +>&2 echo "client-id: $BACKEND_CLIENT_ID" +>&2 echo "username: $USERNAME" +>&2 echo "password: $PASSWORD" +>&2 echo "secure: $SECURE" if [[ $SECURE = 'y' ]]; then @@ -61,7 +68,9 @@ result=$(curl -s -X POST "$KEYCLOAK_URL" "$INSECURE" \ -d "client_id=$BACKEND_CLIENT_ID" \ ) backend_token=$(jq -r '.access_token' <<< "$result") -curl --fail -v "${BACKEND_BASE_URL}/v1.0/process-groups?per_page=1" -H "Authorization: Bearer $backend_token" +echo "$backend_token" +# curl --fail -v "${BACKEND_BASE_URL}/v1.0/process-groups?per_page=1" -H "Authorization: Bearer $backend_token" +# curl -v -X POST "${BACKEND_BASE_URL}/v1.0/login_with_access_token?access_token=${backend_token}" -H "Authorization: Bearer $backend_token" ### Get with frontend and exchange with backend - not configured to work in keycloak atm diff --git a/bin/git_commit_bpmn_models_repo b/bin/git_commit_bpmn_models_repo index 0ba512021..f34400ec5 100755 --- a/bin/git_commit_bpmn_models_repo +++ b/bin/git_commit_bpmn_models_repo @@ -12,12 +12,9 @@ set -o errtrace -o errexit -o nounset -o pipefail bpmn_models_absolute_dir="$1" git_commit_message="$2" git_branch="$3" -git_commit_username="$4" -git_commit_email="$5" -git_commit_password="$6" -if [[ -z "${6:-}" ]]; then - >&2 echo "usage: $(basename "$0") [bpmn_models_absolute_dir] [git_commit_message] [git_branch] [git_commit_username] [git_commit_email]" +if [[ -z "${3:-}" ]]; then + >&2 echo "usage: $(basename "${0}") [bpmn_models_absolute_dir] [git_commit_message] [git_branch]" exit 1 fi @@ -27,26 +24,27 @@ function failed_to_get_lock() { } function run() { - cd "$bpmn_models_absolute_dir" + cd "${bpmn_models_absolute_dir}" git add . # https://unix.stackexchange.com/a/155077/456630 if [ -z "$(git status --porcelain)" ]; then echo "No changes to commit" - else - PAT="${git_commit_username}:${git_commit_password}" - AUTH=$(echo -n "$PAT" | openssl base64 | tr -d '\n') - - git config --local user.name "$git_commit_username" - git config --local user.email "$git_commit_email" - git config --local http.extraHeader "Authorization: Basic $AUTH" - git commit -m "$git_commit_message" - git push --set-upstream origin "$git_branch" - git config --unset --local http.extraHeader + return fi + + # FIXME: the environment variables may not be working with the root user which we are using in the docker container. + # we see some evidence with this issue https://stackoverflow.com/questions/68975943/git-config-environment-variables + # and it didn't seem to work for us either so set them like this for now. + # One day we should probably not use the root user in the docker container. + git config --local user.email "$GIT_COMMITTER_EMAIL" + git config --local user.name "$GIT_COMMITTER_NAME" + + git commit -m "${git_commit_message}" + git push --set-upstream origin "${git_branch}" } -exec {lock_fd}>/var/lock/mylockfile || failed_to_get_lock -flock --timeout 60 "$lock_fd" || failed_to_get_lock +exec {lock_fd}>/var/lock/spiff-workflow-git-lock || failed_to_get_lock +flock --timeout 60 "${lock_fd}" || failed_to_get_lock run -flock -u "$lock_fd" +flock -u "${lock_fd}" diff --git a/bin/import_tickets_for_command_line.py b/bin/import_tickets_for_command_line.py index cc94ba545..c89cc2a74 100644 --- a/bin/import_tickets_for_command_line.py +++ b/bin/import_tickets_for_command_line.py @@ -1,9 +1,8 @@ """Grabs tickets from csv and makes process instances.""" import csv -from flask_bpmn.models.db import db - from spiffworkflow_backend import get_hacked_up_app_for_script +from spiffworkflow_backend.models.db import db from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.user import UserModel from spiffworkflow_backend.services.process_instance_processor import ( diff --git a/bin/import_tickets_for_script_task.py b/bin/import_tickets_for_script_task.py index 6b12699be..1e9f6d196 100644 --- a/bin/import_tickets_for_script_task.py +++ b/bin/import_tickets_for_script_task.py @@ -5,7 +5,7 @@ def main(): """Use main to avoid global namespace.""" import csv - from flask_bpmn.models.db import db + from spiffworkflow_backend.models.db import db from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.user import UserModel diff --git a/bin/login_with_users b/bin/login_with_users new file mode 100755 index 000000000..3d73e036d --- /dev/null +++ b/bin/login_with_users @@ -0,0 +1,40 @@ +#!/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 + +script_dir="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" + +if [[ -z "${KEYCLOAK_BASE_URL:-}" ]]; then + # export KEYCLOAK_BASE_URL=http://localhost:7002 + export KEYCLOAK_BASE_URL=https://keycloak.dev.spiffworkflow.org +fi +if [[ -z "${BACKEND_BASE_URL:-}" ]]; then + # export BACKEND_BASE_URL=http://localhost:7000 + export BACKEND_BASE_URL=https://api.dev.spiffworkflow.org +fi + +user_list="${1}" +if [[ -z "${1:-}" ]]; then + >&2 echo "usage: $(basename "$0") [user_list]" + exit 1 +fi +REALM_NAME=${2-spiffworkflow} + +while read -r input_line; do + if ! grep -qE '(^#|email)' <<<"$input_line" ; then + username=$(awk -F '@' '{print $1}' <<<"$input_line") + access_token=$("${script_dir}/get_token" "$username" "$username" "$REALM_NAME") + if [[ -z "$access_token" || "$access_token" == "null" ]]; then + >&2 echo "ERROR: failed to get access token for '$username'" + else + + echo "access_token: ${access_token}" + curl -v -X POST "${BACKEND_BASE_URL}/v1.0/login_with_access_token?access_token=${access_token}" -H "Authorization: Bearer $access_token" + fi + fi +done <"$user_list" diff --git a/bin/recreate_db b/bin/recreate_db index ec38c7b39..8a78a9b8c 100755 --- a/bin/recreate_db +++ b/bin/recreate_db @@ -9,18 +9,18 @@ set -o errtrace -o errexit -o nounset -o pipefail export FLASK_SESSION_SECRET_KEY="this_is_recreate_db_secret_key" -if [[ -z "${BPMN_SPEC_ABSOLUTE_DIR:-}" ]]; then +if [[ -z "${SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR:-}" ]]; then script_dir="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" - BPMN_SPEC_ABSOLUTE_DIR="${script_dir}/../../../sample-process-models" - if [[ ! -d "$BPMN_SPEC_ABSOLUTE_DIR" ]]; then - BPMN_SPEC_ABSOLUTE_DIR="${script_dir}/../../sample-process-models" - if [[ ! -d "$BPMN_SPEC_ABSOLUTE_DIR" ]]; then - >&2 echo "ERROR: Could not find a location for the sample processes. Last tried: $BPMN_SPEC_ABSOLUTE_DIR" + SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR="${script_dir}/../../../sample-process-models" + if [[ ! -d "$SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR" ]]; then + SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR="${script_dir}/../../sample-process-models" + if [[ ! -d "$SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR" ]]; then + >&2 echo "ERROR: Could not find a location for the sample processes. Last tried: $SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR" exit 1 fi fi - export BPMN_SPEC_ABSOLUTE_DIR + export SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR fi tasks="" @@ -35,33 +35,35 @@ if [[ "${1:-}" == "clean" ]]; then fi rm -f ./src/instance/*.sqlite3 - mysql -uroot -e "DROP DATABASE IF EXISTS spiffworkflow_backend_development" - mysql -uroot -e "DROP DATABASE IF EXISTS spiffworkflow_backend_testing" + mysql -uroot -e "DROP DATABASE IF EXISTS spiffworkflow_backend_local_development" + mysql -uroot -e "DROP DATABASE IF EXISTS spiffworkflow_backend_unit_testing" # TODO: check to see if the db already exists and we can connect to it. also actually clean it up. # start postgres in background with one db - if [[ "${SPIFF_DATABASE_TYPE:-}" == "postgres" ]]; then + if [[ "${SPIFFWORKFLOW_BACKEND_DATABASE_TYPE:-}" == "postgres" ]]; then if ! docker exec -it postgres-spiff psql -U spiffworkflow_backend spiffworkflow_backend_testing -c "select 1"; then docker run --name postgres-spiff -p 5432:5432 -e POSTGRES_PASSWORD=spiffworkflow_backend -e POSTGRES_USER=spiffworkflow_backend -e POSTGRES_DB=spiffworkflow_backend_testing -d postgres sleep 4 # classy fi - if ! docker exec -it postgres-spiff psql -U spiffworkflow_backend spiffworkflow_backend_development -c "select 1"; then + if ! docker exec -it postgres-spiff psql -U spiffworkflow_backend spiffworkflow_backend_local_development -c "select 1"; then # create other db. spiffworkflow_backend_testing came with the docker run. - docker exec -it postgres-spiff psql -U spiffworkflow_backend spiffworkflow_backend_testing -c "create database spiffworkflow_backend_development;" + docker exec -it postgres-spiff psql -U spiffworkflow_backend spiffworkflow_backend_testing -c "create database spiffworkflow_backend_local_development;" fi fi +elif [[ "${1:-}" == "migrate" ]]; then + tasks="$tasks migrate" fi tasks="$tasks upgrade" -mysql -uroot -e "CREATE DATABASE IF NOT EXISTS spiffworkflow_backend_development" -mysql -uroot -e "CREATE DATABASE IF NOT EXISTS spiffworkflow_backend_testing" +mysql -uroot -e "CREATE DATABASE IF NOT EXISTS spiffworkflow_backend_local_development" +mysql -uroot -e "CREATE DATABASE IF NOT EXISTS spiffworkflow_backend_unit_testing" for task in $tasks; do - SPIFFWORKFLOW_BACKEND_ENV=development FLASK_APP=src/spiffworkflow_backend poetry run flask db "$task" + SPIFFWORKFLOW_BACKEND_ENV=local_development FLASK_APP=src/spiffworkflow_backend poetry run flask db "$task" done -SPIFFWORKFLOW_BACKEND_ENV=testing FLASK_APP=src/spiffworkflow_backend poetry run flask db upgrade -if [[ -n "${SPIFFWORKFLOW_BACKEND_ENV:-}" ]] && ! grep -Eq '^(development|testing)$' <<< "$SPIFFWORKFLOW_BACKEND_ENV"; then +SPIFFWORKFLOW_BACKEND_ENV=unit_testing FLASK_APP=src/spiffworkflow_backend poetry run flask db upgrade +if [[ -n "${SPIFFWORKFLOW_BACKEND_ENV:-}" ]] && ! grep -Eq '^(local_development|unit_testing)$' <<< "$SPIFFWORKFLOW_BACKEND_ENV"; then mysql -uroot -e "CREATE DATABASE IF NOT EXISTS spiffworkflow_backend_$SPIFFWORKFLOW_BACKEND_ENV" FLASK_APP=src/spiffworkflow_backend poetry run flask db upgrade fi diff --git a/bin/run_server_locally b/bin/run_server_locally index 0fa63d218..d27ddf3b0 100755 --- a/bin/run_server_locally +++ b/bin/run_server_locally @@ -14,14 +14,14 @@ if [[ "$arg" == "acceptance" ]]; then fi if [[ -z "${SPIFFWORKFLOW_BACKEND_ENV:-}" ]]; then - export SPIFFWORKFLOW_BACKEND_ENV=development + export SPIFFWORKFLOW_BACKEND_ENV=local_development fi -BPMN_SPEC_ABSOLUTE_DIR=$(./bin/find_sample_process_models) -export BPMN_SPEC_ABSOLUTE_DIR +SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR=$(./bin/find_sample_process_models) +export SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR export FLASK_SESSION_SECRET_KEY=super_secret_key -export APPLICATION_ROOT="/" +export SPIFFWORKFLOW_BACKEND_APPLICATION_ROOT="/" if [[ -n "${SPIFFWORKFLOW_BACKEND_LOAD_FIXTURE_DATA:-}" ]]; then ./bin/boot_server_in_docker @@ -29,13 +29,13 @@ else export FLASK_DEBUG=1 if [[ "${SPIFFWORKFLOW_BACKEND_RUN_DATA_SETUP:-}" != "false" ]]; then - RUN_BACKGROUND_SCHEDULER=false SPIFFWORKFLOW_BACKEND_FAIL_ON_INVALID_PROCESS_MODELS=false poetry run python bin/save_all_bpmn.py + SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER=false SPIFFWORKFLOW_BACKEND_FAIL_ON_INVALID_PROCESS_MODELS=false poetry run python bin/save_all_bpmn.py fi - if [[ -z "${RUN_BACKGROUND_SCHEDULER:-}" ]]; then - RUN_BACKGROUND_SCHEDULER=true + if [[ -z "${SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER:-}" ]]; then + SPIFFWORKFLOW_BACKEND_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 + SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER="${SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER}" FLASK_APP=src/spiffworkflow_backend poetry run flask run -p 7000 fi diff --git a/bin/save_to_secrets_from_file b/bin/save_to_secrets_from_file new file mode 100644 index 000000000..5fa1b0bd2 --- /dev/null +++ b/bin/save_to_secrets_from_file @@ -0,0 +1,33 @@ +"""Get the bpmn process json for a given process instance id and store it in /tmp.""" +import os +import sys + +from spiffworkflow_backend import create_app +from spiffworkflow_backend.models.process_instance import ProcessInstanceModel +from spiffworkflow_backend.models.user import UserModel +from spiffworkflow_backend.services.secret_service import SecretService + + +def main(env_file: str): + """Main.""" + os.environ["SPIFFWORKFLOW_BACKEND_ENV"] = "local_development" + if os.environ.get("SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR") is None: + os.environ["SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR"] = "hey" + flask_env_key = "FLASK_SESSION_SECRET_KEY" + os.environ[flask_env_key] = "whatevs" + app = create_app() + with app.app_context(): + contents = None + with open(env_file, 'r') as f: + contents = f.readlines() + for line in contents: + key, value_raw = line.split('=') + value = value_raw.replace('"', '').rstrip() + SecretService().add_secret(key, value, UserModel.query.first().id) + + + +if len(sys.argv) < 2: + raise Exception("env file must be specified") + +main(sys.argv[1]) diff --git a/bin/wait_for_server_to_be_up b/bin/wait_for_server_to_be_up index 4c845613f..04cff3aa5 100755 --- a/bin/wait_for_server_to_be_up +++ b/bin/wait_for_server_to_be_up @@ -7,14 +7,12 @@ function error_handler() { trap 'error_handler ${LINENO} $?' ERR set -o errtrace -o errexit -o nounset -o pipefail -max_attempts="${1:-}" -if [[ -z "$max_attempts" ]]; then - max_attempts=100 -fi +max_attempts="${1:-100}" +port="${2:-7000}" echo "waiting for backend to come up..." attempts=0 -while [[ "$(curl -s -o /dev/null -w '%{http_code}' http://localhost:7000/v1.0/status)" != "200" ]]; do +while [[ "$(curl -s -o /dev/null -w '%{http_code}' "http://localhost:${port}/v1.0/status")" != "200" ]]; do if [[ "$attempts" -gt "$max_attempts" ]]; then >&2 echo "ERROR: Server not up after $max_attempts attempts. There is probably a problem" exit 1 @@ -22,3 +20,4 @@ while [[ "$(curl -s -o /dev/null -w '%{http_code}' http://localhost:7000/v1.0/st attempts=$(( attempts + 1 )) sleep 1 done +echo "backend up" diff --git a/conftest.py b/conftest.py index b24a7ed1b..01fd9e732 100644 --- a/conftest.py +++ b/conftest.py @@ -5,10 +5,10 @@ import shutil import pytest from flask.app import Flask from flask.testing import FlaskClient -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from tests.spiffworkflow_backend.helpers.base_test import BaseTest +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.human_task_user import HumanTaskUserModel from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.user import UserModel @@ -37,7 +37,7 @@ from spiffworkflow_backend import create_app # noqa: E402 @pytest.fixture(scope="session") def app() -> Flask: """App.""" - os.environ["SPIFFWORKFLOW_BACKEND_ENV"] = "testing" + os.environ["SPIFFWORKFLOW_BACKEND_ENV"] = "unit_testing" os.environ["FLASK_SESSION_SECRET_KEY"] = "super_secret_key" app = create_app() diff --git a/docker-compose.yml b/docker-compose.yml index 82e6a1b9c..8fe552812 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,25 +50,25 @@ services: build: context: . environment: - - APPLICATION_ROOT=/ - - SPIFFWORKFLOW_BACKEND_ENV=${SPIFFWORKFLOW_BACKEND_ENV:-development} - FLASK_DEBUG=0 - FLASK_SESSION_SECRET_KEY=${FLASK_SESSION_SECRET_KEY:-super_secret_key} - - OPEN_ID_SERVER_URL=${OPEN_ID_SERVER_URL:-http://localhost:7002/realms/spiffworkflow} - - SPIFFWORKFLOW_FRONTEND_URL=${SPIFFWORKFLOW_FRONTEND_URL:-http://localhost:7001} - - SPIFFWORKFLOW_BACKEND_URL=${SPIFFWORKFLOW_BACKEND_URL:-http://localhost:7000} - - SPIFFWORKFLOW_BACKEND_PORT=7000 - - SPIFFWORKFLOW_BACKEND_UPGRADE_DB=true + - SPIFFWORKFLOW_BACKEND_APPLICATION_ROOT=/ + - SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR=/app/process_models - SPIFFWORKFLOW_BACKEND_DATABASE_URI=mysql+mysqlconnector://root:${SPIFFWORKFLOW_BACKEND_MYSQL_ROOT_DATABASE:-my-secret-pw}@localhost:7003/${SPIFFWORKFLOW_BACKEND_DATABASE_NAME:-spiffworkflow_backend_development} - - BPMN_SPEC_ABSOLUTE_DIR=/app/process_models + - SPIFFWORKFLOW_BACKEND_ENV=${SPIFFWORKFLOW_BACKEND_ENV:-local_development} - SPIFFWORKFLOW_BACKEND_LOAD_FIXTURE_DATA=${SPIFFWORKFLOW_BACKEND_LOAD_FIXTURE_DATA:-false} + - SPIFFWORKFLOW_BACKEND_OPEN_ID_SERVER_URL=${SPIFFWORKFLOW_BACKEND_OPEN_ID_SERVER_URL:-http://localhost:7002/realms/spiffworkflow} - SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME=${SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME:-acceptance_tests.yml} - - RUN_BACKGROUND_SCHEDULER=true + - SPIFFWORKFLOW_BACKEND_PORT=7000 + - SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER=true + - SPIFFWORKFLOW_BACKEND_URL_FOR_FRONTEND=${SPIFFWORKFLOW_BACKEND_URL_FOR_FRONTEND:-http://localhost:7001} + - SPIFFWORKFLOW_BACKEND_UPGRADE_DB=true + - SPIFFWORKFLOW_BACKEND_URL=${SPIFFWORKFLOW_BACKEND_URL:-http://localhost:7000} ports: - "7000:7000" network_mode: host volumes: - - ${BPMN_SPEC_ABSOLUTE_DIR:-../../sample-process-models}:/app/process_models + - ${SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR:-../../sample-process-models}:/app/process_models - ./log:/app/log healthcheck: test: curl localhost:7000/v1.0/status --fail @@ -82,7 +82,7 @@ services: profiles: - debug volumes: - - ${BPMN_SPEC_ABSOLUTE_DIR:-../../sample-process-models}:/app/process_models + - ${SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR:-../../sample-process-models}:/app/process_models - ./:/app command: /app/bin/boot_in_docker_debug_mode diff --git a/keycloak/bin/add_test_users_to_keycloak b/keycloak/bin/add_test_users_to_keycloak index f7cdc6d8c..905823c32 100755 --- a/keycloak/bin/add_test_users_to_keycloak +++ b/keycloak/bin/add_test_users_to_keycloak @@ -7,14 +7,24 @@ function error_handler() { trap 'error_handler ${LINENO} $?' ERR set -o errtrace -o errexit -o nounset -o pipefail +# you can get a list of users from the keycloak realm file like: +# grep '"email" :' keycloak/realm_exports/spiffworkflow-realm.json | awk -F : '{print $2}' | sed -E 's/ "//g' | sed -E 's/",//g' > s + +# we keep some of these in keycloak/test_user_lists +# spiffworkflow-realm.json is a mashup of the status and sartography user lists. user_file_with_one_email_per_line="${1:-}" + +keycloak_realm="${2:-spiffworkflow}" 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 +if [[ -z "${KEYCLOAK_BASE_URL:-}" ]]; then + KEYCLOAK_BASE_URL=http://localhost:7002 +fi + +REALM_NAME="$keycloak_realm" ADMIN_USERNAME="admin" ADMIN_PASSWORD="admin" SECURE=false @@ -37,14 +47,66 @@ result=$(curl --fail -s -X POST "$KEYCLOAK_URL" "$INSECURE" \ ) 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}' +function add_user() { + local user_email=$1 + local username=$2 + local user_attribute_one=$3 - 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}"']}' + local credentials='{"type":"password","value":"'"${username}"'","temporary":false}' + + local data='{"email":"'"${user_email}"'", "enabled":"true", "username":"'"${username}"'", "credentials":['"${credentials}"']' + if [[ -n "$user_attribute_one" ]]; then + data=''${data}', "attributes": {"'${custom_attribute_one}'": [ "'$user_attribute_one'" ]}' + fi + data="${data}}" + + local http_code + http_code=$(curl --silent -o /dev/null -w '%{http_code}' --location --request POST "${KEYCLOAK_BASE_URL}/admin/realms/${keycloak_realm}/users" \ + -H 'Content-Type: application/json' \ + -H "Authorization: Bearer $backend_token" \ + --data-raw "$data") + echo "$http_code" +} + +first_line_processed="false" +custom_attribute_one='' + +while read -r input_line; do + if ! grep -qE '^#' <<<"$input_line" ; then + if [[ "$first_line_processed" == "false" ]]; then + email_header=$(awk -F ',' '{print $1}' <<<"$input_line") + if [[ "$email_header" != "email" ]]; then + >&2 echo "ERROR: the first column in the first row must be email." + exit 1 + fi + custom_attribute_one=$(awk -F ',' '{print $2}' <<<"$input_line") + first_line_processed="true" + elif [[ -n "$input_line" ]]; then + user_email=$(awk -F ',' '{print $1}' <<<"$input_line") + username=$(awk -F '@' '{print $1}' <<<"$user_email") + user_attribute_one=$(awk -F ',' '{print $2}' <<<"$input_line") + http_code=$(add_user "$user_email" "$username" "$user_attribute_one") + + if [[ "$http_code" == "409" ]]; then + user_info=$(curl --fail --silent --location --request GET "${KEYCLOAK_BASE_URL}/admin/realms/${keycloak_realm}/users?username=${username}&exact=true" \ + -H 'Content-Type: application/json' \ + -H "Authorization: Bearer $backend_token") + + user_id=$(jq -r '.[0] | .id' <<<"$user_info") + if [[ -z "$user_id" ]]; then + >&2 echo "ERROR: Could not find user_id for user: ${user_email}" + exit 1 + fi + curl --fail --location --silent --request DELETE "${KEYCLOAK_BASE_URL}/admin/realms/${keycloak_realm}/users/${user_id}" \ + -H 'Content-Type: application/json' \ + -H "Authorization: Bearer $backend_token" + + http_code=$(add_user "$user_email" "$username" "$user_attribute_one") + fi + if [[ "$http_code" != "201" ]]; then + >&2 echo "ERROR: Failed to create user: ${user_email} with http_code: ${http_code}" + exit 1 + fi + fi fi done <"$user_file_with_one_email_per_line" diff --git a/keycloak/bin/export_keycloak_realms b/keycloak/bin/export_keycloak_realms index f205d0d7d..7e55ae6fd 100755 --- a/keycloak/bin/export_keycloak_realms +++ b/keycloak/bin/export_keycloak_realms @@ -21,6 +21,9 @@ 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 + if ! grep -Eq '\-realm$' <<< "$realm"; then + realm="${realm}-realm" + fi cp "${local_tmp_dir}/hey/${realm}.json" "${script_dir}/../realm_exports/" done diff --git a/keycloak/bin/start_keycloak b/keycloak/bin/start_keycloak index de78efad1..242a33751 100755 --- a/keycloak/bin/start_keycloak +++ b/keycloak/bin/start_keycloak @@ -15,6 +15,11 @@ setup_traps set -o errtrace -o errexit -o nounset -o pipefail +realm_name="${1:-}" +if [[ -z "$realm_name" ]]; then + realm_name="spiffworkflow" +fi + if ! docker network inspect spiffworkflow > /dev/null 2>&1; then docker network create spiffworkflow fi @@ -45,15 +50,15 @@ docker run \ -Dkeycloak.profile.feature.admin_fine_grained_authz=enabled script_dir="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" -cp "${script_dir}/../realm_exports/spiffworkflow-realm.json" /tmp/spiffworkflow-realm.json +cp "${script_dir}/../realm_exports/${realm_name}-realm.json" /tmp/${realm_name}-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 +perl -pi -e "s/{{SPIFF_SUBDOMAIN}}/${spiff_subdomain}/g" /tmp/${realm_name}-realm.json +docker cp /tmp/${realm_name}-realm.json keycloak:/tmp sleep 20 remove_traps set +e -import_output=$(docker exec keycloak /opt/keycloak/bin/kc.sh import --file /tmp/spiffworkflow-realm.json 2>&1) +import_output=$(docker exec keycloak /opt/keycloak/bin/kc.sh import --file /tmp/${realm_name}-realm.json 2>&1) setup_traps set -e if ! grep -qE "Import finished successfully" <<<"$import_output"; then @@ -66,7 +71,7 @@ echo 'imported realms' if [ "${TURN_OFF_SSL:-}" == "true" ]; then docker exec -it keycloak /opt/keycloak/bin/kcadm.sh config credentials --server http://localhost:8080 --realm master --user admin --password admin docker exec -it keycloak /opt/keycloak/bin/kcadm.sh update realms/master -s sslRequired=NONE - docker exec -it keycloak /opt/keycloak/bin/kcadm.sh update realms/spiffworkflow -s sslRequired=NONE + docker exec -it keycloak /opt/keycloak/bin/kcadm.sh update realms/${realm_name} -s sslRequired=NONE echo 'turned off SSL requirement' fi diff --git a/keycloak/bin/wait_for_keycloak b/keycloak/bin/wait_for_keycloak index d70184650..1002fb676 100755 --- a/keycloak/bin/wait_for_keycloak +++ b/keycloak/bin/wait_for_keycloak @@ -7,14 +7,12 @@ function error_handler() { trap 'error_handler ${LINENO} $?' ERR set -o errtrace -o errexit -o nounset -o pipefail -max_attempts="${1:-}" -if [[ -z "$max_attempts" ]]; then - max_attempts=100 -fi +max_attempts="${1:-100}" +port="${2:-7002}" -echo "waiting for backend to come up..." +echo "waiting for keycloak to come up..." attempts=0 -while [[ "$(curl -s -o /dev/null -w '%{http_code}' http://localhost:7002/realms/master/.well-known/openid-configuration)" != "200" ]]; do +while [[ "$(curl -s -o /dev/null -w '%{http_code}' "http://localhost:${port}/realms/master/.well-known/openid-configuration")" != "200" ]]; do if [[ "$attempts" -gt "$max_attempts" ]]; then >&2 echo "ERROR: Server not up after $max_attempts attempts. There is probably a problem" exit 1 @@ -22,3 +20,4 @@ while [[ "$(curl -s -o /dev/null -w '%{http_code}' http://localhost:7002/realms/ attempts=$(( attempts + 1 )) sleep 1 done +echo "keycloak up" diff --git a/keycloak/realm_exports/sartography-realm.json b/keycloak/realm_exports/sartography-realm.json new file mode 100644 index 000000000..20c19e24d --- /dev/null +++ b/keycloak/realm_exports/sartography-realm.json @@ -0,0 +1,2552 @@ +{ + "id" : "sartography", + "realm" : "sartography", + "notBefore" : 0, + "defaultSignatureAlgorithm" : "RS256", + "revokeRefreshToken" : false, + "refreshTokenMaxReuse" : 0, + "accessTokenLifespan" : 1800, + "accessTokenLifespanForImplicitFlow" : 900, + "ssoSessionIdleTimeout" : 86400, + "ssoSessionMaxLifespan" : 864000, + "ssoSessionIdleTimeoutRememberMe" : 0, + "ssoSessionMaxLifespanRememberMe" : 0, + "offlineSessionIdleTimeout" : 2592000, + "offlineSessionMaxLifespanEnabled" : false, + "offlineSessionMaxLifespan" : 5184000, + "clientSessionIdleTimeout" : 0, + "clientSessionMaxLifespan" : 0, + "clientOfflineSessionIdleTimeout" : 0, + "clientOfflineSessionMaxLifespan" : 0, + "accessCodeLifespan" : 60, + "accessCodeLifespanUserAction" : 300, + "accessCodeLifespanLogin" : 1800, + "actionTokenGeneratedByAdminLifespan" : 43200, + "actionTokenGeneratedByUserLifespan" : 300, + "oauth2DeviceCodeLifespan" : 600, + "oauth2DevicePollingInterval" : 5, + "enabled" : true, + "sslRequired" : "external", + "registrationAllowed" : false, + "registrationEmailAsUsername" : false, + "rememberMe" : false, + "verifyEmail" : false, + "loginWithEmailAllowed" : true, + "duplicateEmailsAllowed" : false, + "resetPasswordAllowed" : false, + "editUsernameAllowed" : false, + "bruteForceProtected" : false, + "permanentLockout" : false, + "maxFailureWaitSeconds" : 900, + "minimumQuickLoginWaitSeconds" : 60, + "waitIncrementSeconds" : 60, + "quickLoginCheckMilliSeconds" : 1000, + "maxDeltaTimeSeconds" : 43200, + "failureFactor" : 30, + "roles" : { + "realm" : [ { + "id" : "c9f0ff93-642d-402b-965a-04d70719886b", + "name" : "default-roles-sartography", + "description" : "${role_default-roles}", + "composite" : true, + "composites" : { + "realm" : [ "offline_access", "uma_authorization" ], + "client" : { + "account" : [ "view-profile", "manage-account" ] + } + }, + "clientRole" : false, + "containerId" : "sartography", + "attributes" : { } + }, { + "id" : "9f474167-5707-4c10-8f9e-bb54ec715cd3", + "name" : "uma_authorization", + "description" : "${role_uma_authorization}", + "composite" : false, + "clientRole" : false, + "containerId" : "sartography", + "attributes" : { } + }, { + "id" : "6738d143-2d1d-4458-8a98-01ea003fde14", + "name" : "admin", + "composite" : false, + "clientRole" : false, + "containerId" : "sartography", + "attributes" : { } + }, { + "id" : "6cbcdea5-0083-469d-9576-1d245fb3cdfd", + "name" : "repeat-form-role-realm", + "composite" : false, + "clientRole" : false, + "containerId" : "sartography", + "attributes" : { } + }, { + "id" : "b5a92aee-82d2-4687-8282-365df4df21a9", + "name" : "offline_access", + "description" : "${role_offline-access}", + "composite" : false, + "clientRole" : false, + "containerId" : "sartography", + "attributes" : { } + } ], + "client" : { + "realm-management" : [ { + "id" : "257c348c-4b9e-4fea-be39-5fdd28e8bb93", + "name" : "manage-authorization", + "description" : "${role_manage-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "1d224265-63a8-40ea-9316-47627d0aed8c", + "name" : "view-authorization", + "description" : "${role_view-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "535d7ca0-0f06-42d8-938b-e6e7aabffb42", + "name" : "query-groups", + "description" : "${role_query-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "9ff52ab5-2558-4cb0-901f-6e6f1469d075", + "name" : "realm-admin", + "description" : "${role_realm-admin}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "manage-authorization", "view-authorization", "query-groups", "view-clients", "view-realm", "manage-users", "query-users", "impersonation", "manage-clients", "view-identity-providers", "create-client", "query-realms", "view-users", "view-events", "manage-identity-providers", "manage-events", "query-clients", "manage-realm" ] + } + }, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "98db35e3-833f-4b61-83af-fc50484fda57", + "name" : "view-clients", + "description" : "${role_view-clients}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-clients" ] + } + }, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "e0dc0e0c-eba4-4de7-b2eb-2ba095c4c6d4", + "name" : "manage-users", + "description" : "${role_manage-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "69ce3805-1897-4291-842b-b8e8e9f29bd7", + "name" : "view-realm", + "description" : "${role_view-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "3e803641-96b1-44d8-9de5-7dee83a0a75b", + "name" : "impersonation", + "description" : "${role_impersonation}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "2c92c3e5-1a0a-4318-9b63-617c5dca0b66", + "name" : "query-users", + "description" : "${role_query-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "326a3718-390d-4e41-af00-2197d3ef6858", + "name" : "manage-clients", + "description" : "${role_manage-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "e4c69181-5e0d-484e-ac31-be6beef57c28", + "name" : "create-client", + "description" : "${role_create-client}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "f4ac66cc-97b4-4590-beae-5ff23c9935b3", + "name" : "query-realms", + "description" : "${role_query-realms}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "a24704fe-13fd-40e6-bf2d-29014f63c069", + "name" : "view-identity-providers", + "description" : "${role_view-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "7deec87c-2716-40c1-a115-2a0fe840b119", + "name" : "view-users", + "description" : "${role_view-users}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-groups", "query-users" ] + } + }, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "827c40ae-b4c2-4574-9f34-db33925cd19c", + "name" : "view-events", + "description" : "${role_view-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "cbe05c62-2b07-4ac7-a33a-ffca7c176252", + "name" : "manage-events", + "description" : "${role_manage-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "8ca56814-a817-4849-a515-45399eb1dcc1", + "name" : "manage-identity-providers", + "description" : "${role_manage-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "1134c6df-d0ff-498d-9dc4-ad989f7cfe93", + "name" : "query-clients", + "description" : "${role_query-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + }, { + "id" : "3bb14549-60f6-4078-8f4e-47a1162412f2", + "name" : "manage-realm", + "description" : "${role_manage-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "attributes" : { } + } ], + "spiffworkflow-frontend" : [ ], + "security-admin-console" : [ ], + "admin-cli" : [ ], + "spiffworkflow-backend" : [ { + "id" : "4d71d1bb-d627-43c8-bc07-d542f816e04b", + "name" : "sartography-admin", + "composite" : false, + "clientRole" : true, + "containerId" : "f44558af-3601-4e54-b854-08396a247544", + "attributes" : { } + }, { + "id" : "2341ca1c-24c8-4ddf-874c-7153c9408068", + "name" : "uma_protection", + "composite" : false, + "clientRole" : true, + "containerId" : "f44558af-3601-4e54-b854-08396a247544", + "attributes" : { } + }, { + "id" : "cf88054e-4bdc-491c-bf93-c660cdaad72d", + "name" : "repeat-form-role-2", + "composite" : false, + "clientRole" : true, + "containerId" : "f44558af-3601-4e54-b854-08396a247544", + "attributes" : { + "repeat-form-role-2-att-key" : [ "repeat-form-role-2-att-value" ] + } + } ], + "withAuth" : [ { + "id" : "87673823-6a5a-4cb2-baa7-6c8b5da5d402", + "name" : "uma_protection", + "composite" : false, + "clientRole" : true, + "containerId" : "5d94a8c3-f56b-4eff-ac39-8580053a7fbe", + "attributes" : { } + } ], + "broker" : [ { + "id" : "6d688d72-cf5b-4450-a902-cb2d41f0e04c", + "name" : "read-token", + "description" : "${role_read-token}", + "composite" : false, + "clientRole" : true, + "containerId" : "55d75754-cf1b-4875-bf3e-15add4be8c99", + "attributes" : { } + } ], + "account" : [ { + "id" : "9c51c3e1-028d-4a0d-96dc-6619196b49f0", + "name" : "delete-account", + "description" : "${role_delete-account}", + "composite" : false, + "clientRole" : true, + "containerId" : "e39b3c85-bb9d-4c73-8250-be087c82ae48", + "attributes" : { } + }, { + "id" : "f395d221-7f80-4fcf-90ac-0a89c8b15a9b", + "name" : "manage-consent", + "description" : "${role_manage-consent}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "view-consent" ] + } + }, + "clientRole" : true, + "containerId" : "e39b3c85-bb9d-4c73-8250-be087c82ae48", + "attributes" : { } + }, { + "id" : "7abb4169-1960-4b4d-b5ae-6ea45cf91ee4", + "name" : "view-consent", + "description" : "${role_view-consent}", + "composite" : false, + "clientRole" : true, + "containerId" : "e39b3c85-bb9d-4c73-8250-be087c82ae48", + "attributes" : { } + }, { + "id" : "4d3c24ed-cc61-4a6e-ac78-47af4545b415", + "name" : "manage-account-links", + "description" : "${role_manage-account-links}", + "composite" : false, + "clientRole" : true, + "containerId" : "e39b3c85-bb9d-4c73-8250-be087c82ae48", + "attributes" : { } + }, { + "id" : "a4954091-9be9-4b7c-a196-1af934917ff7", + "name" : "view-profile", + "description" : "${role_view-profile}", + "composite" : false, + "clientRole" : true, + "containerId" : "e39b3c85-bb9d-4c73-8250-be087c82ae48", + "attributes" : { } + }, { + "id" : "0810773c-a57d-449e-a31f-1344e1eb4b9b", + "name" : "manage-account", + "description" : "${role_manage-account}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "manage-account-links" ] + } + }, + "clientRole" : true, + "containerId" : "e39b3c85-bb9d-4c73-8250-be087c82ae48", + "attributes" : { } + }, { + "id" : "f75e4973-b9b6-4ff0-a691-5f900199b17a", + "name" : "view-groups", + "description" : "${role_view-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "e39b3c85-bb9d-4c73-8250-be087c82ae48", + "attributes" : { } + }, { + "id" : "ae774a41-a274-4f99-9d7f-f4a0d5dbc085", + "name" : "view-applications", + "description" : "${role_view-applications}", + "composite" : false, + "clientRole" : true, + "containerId" : "e39b3c85-bb9d-4c73-8250-be087c82ae48", + "attributes" : { } + } ] + } + }, + "groups" : [ ], + "defaultRole" : { + "id" : "c9f0ff93-642d-402b-965a-04d70719886b", + "name" : "default-roles-sartography", + "description" : "${role_default-roles}", + "composite" : true, + "clientRole" : false, + "containerId" : "sartography" + }, + "requiredCredentials" : [ "password" ], + "otpPolicyType" : "totp", + "otpPolicyAlgorithm" : "HmacSHA1", + "otpPolicyInitialCounter" : 0, + "otpPolicyDigits" : 6, + "otpPolicyLookAheadWindow" : 1, + "otpPolicyPeriod" : 30, + "otpPolicyCodeReusable" : false, + "otpSupportedApplications" : [ "totpAppGoogleName", "totpAppFreeOTPName" ], + "webAuthnPolicyRpEntityName" : "keycloak", + "webAuthnPolicySignatureAlgorithms" : [ "ES256" ], + "webAuthnPolicyRpId" : "", + "webAuthnPolicyAttestationConveyancePreference" : "not specified", + "webAuthnPolicyAuthenticatorAttachment" : "not specified", + "webAuthnPolicyRequireResidentKey" : "not specified", + "webAuthnPolicyUserVerificationRequirement" : "not specified", + "webAuthnPolicyCreateTimeout" : 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyAcceptableAaguids" : [ ], + "webAuthnPolicyPasswordlessRpEntityName" : "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256" ], + "webAuthnPolicyPasswordlessRpId" : "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified", + "webAuthnPolicyPasswordlessCreateTimeout" : 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ], + "users" : [ { + "id" : "b1962f0b-ab27-4942-a6fe-739986a8e828", + "createdTimestamp" : 1674241681084, + "username" : "admin", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "firstName" : "", + "lastName" : "", + "email" : "admin@spiffworkflow.org", + "credentials" : [ { + "id" : "d696d69c-d1bc-4672-8253-e2053742dd77", + "type" : "password", + "userLabel" : "My password", + "createdDate" : 1674241688962, + "secretData" : "{\"value\":\"xUnlqGFcEeaKrOGA/Xe8O6p9wUvwzoa7cNS4Fb9TVEvIppNanHLuwcVV5WldiPIqgn6Wp5s5vsHG9CGbkcTLtQ==\",\"salt\":\"S6Iw+GlwpNogVEb74baEIA==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-sartography" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "5909d4ca-a335-4357-89f9-4da00e2401a9", + "createdTimestamp" : 1674155681384, + "username" : "alex", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "alex@sartography.com", + "credentials" : [ { + "id" : "45ccdf71-0dfb-4b18-9e49-fe33eca3f597", + "type" : "password", + "createdDate" : 1674155681461, + "secretData" : "{\"value\":\"WjDxX/DCj2iQactiesdMbtHIqhNtYaMgIELU+FT5LRQtkrQSc/0a4PAgRMqG3TMXUQyObMbaCVcGbgFVaQ37iw==\",\"salt\":\"jOJsyZ07hzQ6bP31lc3oQg==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-sartography" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "c6e9c043-2742-407a-a74e-2780939d157a", + "createdTimestamp" : 1674155681499, + "username" : "dan", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "dan@sartography.com", + "credentials" : [ { + "id" : "a51701c6-3d1b-410b-8405-795419896981", + "type" : "password", + "createdDate" : 1674155681550, + "secretData" : "{\"value\":\"+Fv4PPJ2SFWP8eDx1blXll42i48LIBs2O1/jy4ZNKurw2MjBtsr3+Vf66dEzyS9mmoMduYp9XY/ByTmKVE4iwQ==\",\"salt\":\"J0sI50S40dsaLLrHPCehCQ==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-sartography" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "401bf2ee-598f-42cf-b8dc-d602b88b3c17", + "createdTimestamp" : 1674155681783, + "username" : "elizabeth", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "elizabeth@sartography.com", + "credentials" : [ { + "id" : "9533921a-f546-4490-a817-c819bd1ef0e6", + "type" : "password", + "createdDate" : 1674155681830, + "secretData" : "{\"value\":\"mZlp4+1ekdSHK0KxruMrrerSah5cUXVsiwuWQpfZXR+vO6s9pL0apnjyP3Wh9UUMC1EEIhistJ1s8H29HkBLFQ==\",\"salt\":\"Uhr9apu4+WaMBu6jMUflLw==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-sartography" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "2b286bd4-7d2d-47ff-bcc4-8f3df8ae58a3", + "createdTimestamp" : 1674155681655, + "username" : "jason", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "jason@sartography.com", + "credentials" : [ { + "id" : "3d87310a-6ba1-4119-ae6a-bbabb09ef83e", + "type" : "password", + "createdDate" : 1674155681705, + "secretData" : "{\"value\":\"trHjxSyknzqHHalAzQ7zXwNLeAY2sn7JBbfOdhaoEd2EOUhJuwwKiJxFSBJ8TwlMDMzgZ4ggm5U+jWIw+QXcIQ==\",\"salt\":\"ZbSqDz+ZEq5o2dNc2C+tXA==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-sartography" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "98b419a4-3af6-42e3-85a0-6e21fade523f", + "createdTimestamp" : 1674155681852, + "username" : "jon", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "jon@sartography.com", + "credentials" : [ { + "id" : "f6ada744-fd58-4fb2-80a0-d57536d9151a", + "type" : "password", + "createdDate" : 1674155681904, + "secretData" : "{\"value\":\"RZK7tk7LUzm5/RhcDMKM30EKxkzzTXb0cIHR5l0XFx1+uSouynPuWocBysDlczl5BpQTt1hQ8ntsTMCme/OqAw==\",\"salt\":\"A/fAf3q1bUsnKrZBg7KTDA==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-sartography" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "7622036a-33ff-4f51-b28c-c82cad4cf656", + "createdTimestamp" : 1674155681576, + "username" : "kevin", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "kb@sartography.com", + "credentials" : [ { + "id" : "4057e784-689d-47c0-a164-035a69e78edf", + "type" : "password", + "createdDate" : 1674155681624, + "secretData" : "{\"value\":\"P4C9Vyg9qcn+xt7HujmW8mGYGuaNoN7dbn1VT6P2R6A0Uhq4XqRsceLzoedflvmX50HuJpi8LJCPadyuYjZnYw==\",\"salt\":\"5F3ca6zImOZD77tRnTXANA==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-sartography" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "5139bbaa-6651-4795-87ed-fcfaf040729d", + "createdTimestamp" : 1674155681720, + "username" : "mike", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "mike@sartography.com", + "credentials" : [ { + "id" : "5a0256ec-e107-4e7c-be8a-30b5d487aaab", + "type" : "password", + "createdDate" : 1674155681767, + "secretData" : "{\"value\":\"7Lo58G8ZRoAq0VNH/47zwarKodTfaq2V5m87XetyJRpDeJaBsTjC5dl2NfyCtb0i3czF9Qvq8fFumTpiUmvZVw==\",\"salt\":\"6/dQoi1YSLB/LeGmZUXwQw==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-sartography" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "f2e357d0-6415-4665-9778-7d903b456ca3", + "createdTimestamp" : 1674155681926, + "username" : "natalia", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "natalia@sartography.com", + "credentials" : [ { + "id" : "019655ea-1b07-40db-a379-11110cd13b57", + "type" : "password", + "createdDate" : 1674155681974, + "secretData" : "{\"value\":\"ammEbT6wDlOiCdv1EJaF2NBhhwd0P3+442aw6xl3WL3UwJ9nNtx5+OVT8pmwAvhbnq15RDX4OuzYfPsSCPXCdA==\",\"salt\":\"rXXtaEaE4TOOE6r0DA1FIA==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-sartography" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "00ec8958-cfc7-4c6a-ab59-1d3a594e81b1", + "createdTimestamp" : 1674155517688, + "username" : "service-account-spiffworkflow-backend", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "serviceAccountClientId" : "spiffworkflow-backend", + "credentials" : [ ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-sartography" ], + "clientRoles" : { + "spiffworkflow-backend" : [ "uma_protection" ] + }, + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "054dc2e7-69bb-4711-9c34-ec1e9600fe32", + "createdTimestamp" : 1674155517792, + "username" : "service-account-withauth", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "serviceAccountClientId" : "withAuth", + "credentials" : [ ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-sartography" ], + "clientRoles" : { + "withAuth" : [ "uma_protection" ] + }, + "notBefore" : 0, + "groups" : [ ] + } ], + "scopeMappings" : [ { + "clientScope" : "offline_access", + "roles" : [ "offline_access" ] + } ], + "clients" : [ { + "id" : "e39b3c85-bb9d-4c73-8250-be087c82ae48", + "clientId" : "account", + "name" : "${client_account}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/sartography/account/", + "surrogateAuthRequired" : false, + "enabled" : false, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/realms/sartography/account/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "saml.force.post.binding" : "false", + "saml.multivalued.roles" : "false", + "frontchannel.logout.session.required" : "false", + "post.logout.redirect.uris" : "+", + "oauth2.device.authorization.grant.enabled" : "false", + "backchannel.logout.revoke.offline.tokens" : "false", + "saml.server.signature.keyinfo.ext" : "false", + "use.refresh.tokens" : "true", + "oidc.ciba.grant.enabled" : "false", + "backchannel.logout.session.required" : "false", + "client_credentials.use_refresh_token" : "false", + "require.pushed.authorization.requests" : "false", + "saml.client.signature" : "false", + "saml.allow.ecp.flow" : "false", + "id.token.as.detached.signature" : "false", + "saml.assertion.signature" : "false", + "saml.encrypt" : "false", + "saml.server.signature" : "false", + "exclude.session.state.from.auth.response" : "false", + "saml.artifact.binding" : "false", + "saml_force_name_id_format" : "false", + "acr.loa.map" : "{}", + "tls.client.certificate.bound.access.tokens" : "false", + "saml.authnstatement" : "false", + "display.on.consent.screen" : "false", + "token.response.type.bearer.lower-case" : "false", + "saml.onetimeuse.condition" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "02fa6179-9399-4bb1-970f-c4d8e8b5f99f", + "clientId" : "admin-cli", + "name" : "${client_admin-cli}", + "surrogateAuthRequired" : false, + "enabled" : false, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : false, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "saml.force.post.binding" : "false", + "saml.multivalued.roles" : "false", + "frontchannel.logout.session.required" : "false", + "post.logout.redirect.uris" : "+", + "oauth2.device.authorization.grant.enabled" : "false", + "backchannel.logout.revoke.offline.tokens" : "false", + "saml.server.signature.keyinfo.ext" : "false", + "use.refresh.tokens" : "true", + "oidc.ciba.grant.enabled" : "false", + "backchannel.logout.session.required" : "false", + "client_credentials.use_refresh_token" : "false", + "require.pushed.authorization.requests" : "false", + "saml.client.signature" : "false", + "saml.allow.ecp.flow" : "false", + "id.token.as.detached.signature" : "false", + "saml.assertion.signature" : "false", + "saml.encrypt" : "false", + "saml.server.signature" : "false", + "exclude.session.state.from.auth.response" : "false", + "saml.artifact.binding" : "false", + "saml_force_name_id_format" : "false", + "acr.loa.map" : "{}", + "tls.client.certificate.bound.access.tokens" : "false", + "saml.authnstatement" : "false", + "display.on.consent.screen" : "false", + "token.response.type.bearer.lower-case" : "false", + "saml.onetimeuse.condition" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "55d75754-cf1b-4875-bf3e-15add4be8c99", + "clientId" : "broker", + "name" : "${client_broker}", + "surrogateAuthRequired" : false, + "enabled" : false, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : true, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "saml.force.post.binding" : "false", + "saml.multivalued.roles" : "false", + "frontchannel.logout.session.required" : "false", + "post.logout.redirect.uris" : "+", + "oauth2.device.authorization.grant.enabled" : "false", + "backchannel.logout.revoke.offline.tokens" : "false", + "saml.server.signature.keyinfo.ext" : "false", + "use.refresh.tokens" : "true", + "oidc.ciba.grant.enabled" : "false", + "backchannel.logout.session.required" : "false", + "client_credentials.use_refresh_token" : "false", + "require.pushed.authorization.requests" : "false", + "saml.client.signature" : "false", + "saml.allow.ecp.flow" : "false", + "id.token.as.detached.signature" : "false", + "saml.assertion.signature" : "false", + "saml.encrypt" : "false", + "saml.server.signature" : "false", + "exclude.session.state.from.auth.response" : "false", + "saml.artifact.binding" : "false", + "saml_force_name_id_format" : "false", + "acr.loa.map" : "{}", + "tls.client.certificate.bound.access.tokens" : "false", + "saml.authnstatement" : "false", + "display.on.consent.screen" : "false", + "token.response.type.bearer.lower-case" : "false", + "saml.onetimeuse.condition" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "4ce68130-aced-4e67-936a-8082dc843cc2", + "clientId" : "realm-management", + "name" : "${client_realm-management}", + "surrogateAuthRequired" : false, + "enabled" : false, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : true, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "saml.force.post.binding" : "false", + "saml.multivalued.roles" : "false", + "frontchannel.logout.session.required" : "false", + "post.logout.redirect.uris" : "+", + "oauth2.device.authorization.grant.enabled" : "false", + "backchannel.logout.revoke.offline.tokens" : "false", + "saml.server.signature.keyinfo.ext" : "false", + "use.refresh.tokens" : "true", + "oidc.ciba.grant.enabled" : "false", + "backchannel.logout.session.required" : "false", + "client_credentials.use_refresh_token" : "false", + "require.pushed.authorization.requests" : "false", + "saml.client.signature" : "false", + "saml.allow.ecp.flow" : "false", + "id.token.as.detached.signature" : "false", + "saml.assertion.signature" : "false", + "saml.encrypt" : "false", + "saml.server.signature" : "false", + "exclude.session.state.from.auth.response" : "false", + "saml.artifact.binding" : "false", + "saml_force_name_id_format" : "false", + "acr.loa.map" : "{}", + "tls.client.certificate.bound.access.tokens" : "false", + "saml.authnstatement" : "false", + "display.on.consent.screen" : "false", + "token.response.type.bearer.lower-case" : "false", + "saml.onetimeuse.condition" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "7c82344d-d4ae-4599-bbce-583cc8848199", + "clientId" : "security-admin-console", + "name" : "${client_security-admin-console}", + "rootUrl" : "${authAdminUrl}", + "baseUrl" : "/admin/sartography/console/", + "surrogateAuthRequired" : false, + "enabled" : false, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/admin/sartography/console/*" ], + "webOrigins" : [ "+" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "saml.force.post.binding" : "false", + "saml.multivalued.roles" : "false", + "frontchannel.logout.session.required" : "false", + "post.logout.redirect.uris" : "+", + "oauth2.device.authorization.grant.enabled" : "false", + "backchannel.logout.revoke.offline.tokens" : "false", + "saml.server.signature.keyinfo.ext" : "false", + "use.refresh.tokens" : "true", + "oidc.ciba.grant.enabled" : "false", + "backchannel.logout.session.required" : "false", + "client_credentials.use_refresh_token" : "false", + "require.pushed.authorization.requests" : "false", + "saml.client.signature" : "false", + "pkce.code.challenge.method" : "S256", + "saml.allow.ecp.flow" : "false", + "id.token.as.detached.signature" : "false", + "saml.assertion.signature" : "false", + "saml.encrypt" : "false", + "saml.server.signature" : "false", + "exclude.session.state.from.auth.response" : "false", + "saml.artifact.binding" : "false", + "saml_force_name_id_format" : "false", + "acr.loa.map" : "{}", + "tls.client.certificate.bound.access.tokens" : "false", + "saml.authnstatement" : "false", + "display.on.consent.screen" : "false", + "token.response.type.bearer.lower-case" : "false", + "saml.onetimeuse.condition" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "protocolMappers" : [ { + "id" : "949c8afa-a06e-4a86-9260-6f477fc9ad9d", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "f44558af-3601-4e54-b854-08396a247544", + "clientId" : "spiffworkflow-backend", + "name" : "", + "description" : "", + "rootUrl" : "", + "adminUrl" : "", + "baseUrl" : "", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "JXeQExm0JhQPLumgHtIIqf52bDalHz0q", + "redirectUris" : [ "http://localhost:7000/*", "https://api.unused-for-local-dev.spiffworkflow.org/*", "https://api.replace-me-with-spiff-subdomain.spiffworkflow.org/*", "http://67.205.133.116:7000/*", "http://167.172.242.138:7000/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : true, + "authorizationServicesEnabled" : true, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "saml.force.post.binding" : "false", + "saml.multivalued.roles" : "false", + "frontchannel.logout.session.required" : "false", + "post.logout.redirect.uris" : "https://replace-me-with-spiff-subdomain.spiffworkflow.org/*##http://localhost:7001/*", + "oauth2.device.authorization.grant.enabled" : "false", + "backchannel.logout.revoke.offline.tokens" : "false", + "saml.server.signature.keyinfo.ext" : "false", + "use.refresh.tokens" : "true", + "oidc.ciba.grant.enabled" : "false", + "backchannel.logout.session.required" : "true", + "client_credentials.use_refresh_token" : "false", + "require.pushed.authorization.requests" : "false", + "saml.client.signature" : "false", + "saml.allow.ecp.flow" : "false", + "id.token.as.detached.signature" : "false", + "saml.assertion.signature" : "false", + "client.secret.creation.time" : "1657115173", + "saml.encrypt" : "false", + "saml.server.signature" : "false", + "exclude.session.state.from.auth.response" : "false", + "saml.artifact.binding" : "false", + "saml_force_name_id_format" : "false", + "acr.loa.map" : "{}", + "tls.client.certificate.bound.access.tokens" : "false", + "saml.authnstatement" : "false", + "display.on.consent.screen" : "false", + "token.response.type.bearer.lower-case" : "false", + "saml.onetimeuse.condition" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : -1, + "protocolMappers" : [ { + "id" : "af3598ab-74a9-48ba-956f-431b14acd896", + "name" : "Client IP Address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientAddress", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientAddress", + "jsonType.label" : "String" + } + }, { + "id" : "87369cf7-2a77-40fd-a926-a26d689831a0", + "name" : "Client Host", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientHost", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientHost", + "jsonType.label" : "String" + } + }, { + "id" : "2c78d7e8-0a99-43bd-bc29-0ba062ed8750", + "name" : "Client ID", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientId", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientId", + "jsonType.label" : "String" + } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ], + "authorizationSettings" : { + "allowRemoteResourceManagement" : true, + "policyEnforcementMode" : "ENFORCING", + "resources" : [ { + "name" : "everything", + "ownerManagedAccess" : false, + "attributes" : { }, + "_id" : "446bdcf4-a3bd-41c7-a0f8-67a225ba6b57", + "uris" : [ "/*" ], + "scopes" : [ { + "name" : "read" + }, { + "name" : "update" + }, { + "name" : "delete" + }, { + "name" : "instantiate" + } ] + }, { + "name" : "Default Resource", + "type" : "urn:spiffworkflow-backend:resources:default", + "ownerManagedAccess" : false, + "attributes" : { }, + "_id" : "8e00e4a3-3fff-4521-b7f0-95f66c2f79d2", + "uris" : [ "/*" ] + }, { + "name" : "process-model-with-repeating-form-crud", + "type" : "process-model", + "ownerManagedAccess" : false, + "displayName" : "process-model-with-repeating-form-crud", + "attributes" : { + "test_resource_att1" : [ "this_is_the_value" ] + }, + "_id" : "e294304c-796e-4c56-bdf2-8c854f65db59", + "uris" : [ "/process-models/category_number_one/process-model-with-repeating-form" ], + "scopes" : [ { + "name" : "read" + }, { + "name" : "update" + }, { + "name" : "delete" + }, { + "name" : "instantiate" + } ] + } ], + "policies" : [ { + "id" : "048d043e-d98c-44d8-8c85-656ba117053e", + "name" : "repeat-form-role-policy", + "type" : "role", + "logic" : "POSITIVE", + "decisionStrategy" : "UNANIMOUS", + "config" : { + "roles" : "[{\"id\":\"spiffworkflow-backend/repeat-form-role-2\",\"required\":false}]" + } + }, { + "id" : "ac55237b-6ec9-4f66-bb8e-bee94a5bb5e9", + "name" : "admins have everything", + "type" : "role", + "logic" : "POSITIVE", + "decisionStrategy" : "UNANIMOUS", + "config" : { + "roles" : "[{\"id\":\"spiffworkflow-backend/sartography-admin\",\"required\":false}]" + } + }, { + "id" : "7dac9bea-d415-4bc4-8817-7a71c2b3ce32", + "name" : "Default Policy", + "description" : "A policy that grants access only for users within this realm", + "type" : "role", + "logic" : "POSITIVE", + "decisionStrategy" : "AFFIRMATIVE", + "config" : { + "roles" : "[{\"id\":\"spiffworkflow-backend/repeat-form-role-2\",\"required\":false}]" + } + }, { + "id" : "5133ae0b-5e90-48a6-bdd9-3f323e10c44d", + "name" : "repeat-form-read", + "type" : "scope", + "logic" : "POSITIVE", + "decisionStrategy" : "UNANIMOUS", + "config" : { + "resources" : "[\"process-model-with-repeating-form-crud\"]", + "scopes" : "[\"read\"]", + "applyPolicies" : "[\"repeat-form-role-policy\"]" + } + }, { + "id" : "0a86ae38-7460-4bc2-b1f9-f933531303ac", + "name" : "all_permissions", + "type" : "resource", + "logic" : "POSITIVE", + "decisionStrategy" : "UNANIMOUS", + "config" : { + "resources" : "[\"everything\"]", + "applyPolicies" : "[\"admins have everything\"]" + } + }, { + "id" : "4b634627-51d9-4257-91d9-29503490e4fb", + "name" : "Default Permission", + "description" : "A permission that applies to the default resource type", + "type" : "resource", + "logic" : "POSITIVE", + "decisionStrategy" : "UNANIMOUS", + "config" : { + "defaultResourceType" : "urn:spiffworkflow-backend:resources:default", + "applyPolicies" : "[\"Default Policy\"]" + } + } ], + "scopes" : [ { + "id" : "c03b5c4e-f1bb-4066-8666-3c8a6f44ddb3", + "name" : "read", + "displayName" : "read" + }, { + "id" : "f55c3e81-9257-4618-9acb-32c57fc561a6", + "name" : "update", + "displayName" : "update" + }, { + "id" : "c8628417-7ffa-4675-9cda-955df62ea1db", + "name" : "delete", + "displayName" : "delete" + }, { + "id" : "50ef4129-aa88-4ecd-9afe-c7e5a1b66142", + "name" : "instantiate", + "displayName" : "instantiate" + } ], + "decisionStrategy" : "UNANIMOUS" + } + }, { + "id" : "9f340eba-2b84-43d0-a976-010e270e3981", + "clientId" : "spiffworkflow-frontend", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "https://api.unused-for-local-dev.spiffworkflow.org/*", "http://localhost:7001/*", "http://67.205.133.116:7000/*", "http://167.172.242.138:7001/*", "https://api.demo.spiffworkflow.org/*" ], + "webOrigins" : [ "*" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "saml.force.post.binding" : "false", + "saml.multivalued.roles" : "false", + "frontchannel.logout.session.required" : "false", + "post.logout.redirect.uris" : "+", + "oauth2.device.authorization.grant.enabled" : "false", + "backchannel.logout.revoke.offline.tokens" : "false", + "saml.server.signature.keyinfo.ext" : "false", + "use.refresh.tokens" : "true", + "oidc.ciba.grant.enabled" : "false", + "backchannel.logout.session.required" : "true", + "client_credentials.use_refresh_token" : "false", + "require.pushed.authorization.requests" : "false", + "saml.client.signature" : "false", + "saml.allow.ecp.flow" : "false", + "id.token.as.detached.signature" : "false", + "saml.assertion.signature" : "false", + "saml.encrypt" : "false", + "saml.server.signature" : "false", + "exclude.session.state.from.auth.response" : "false", + "saml.artifact.binding" : "false", + "saml_force_name_id_format" : "false", + "acr.loa.map" : "{}", + "tls.client.certificate.bound.access.tokens" : "false", + "saml.authnstatement" : "false", + "display.on.consent.screen" : "false", + "token.response.type.bearer.lower-case" : "false", + "saml.onetimeuse.condition" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : -1, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "5d94a8c3-f56b-4eff-ac39-8580053a7fbe", + "clientId" : "withAuth", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "6o8kIKQznQtejHOdRhWeKorBJclMGcgA", + "redirectUris" : [ "https://api.unused-for-local-dev.spiffworkflow.org/*", "http://localhost:7001/*", "http://67.205.133.116:7000/*", "http://167.172.242.138:7001/*", "https://api.demo.spiffworkflow.org/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : true, + "authorizationServicesEnabled" : true, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "saml.force.post.binding" : "false", + "saml.multivalued.roles" : "false", + "frontchannel.logout.session.required" : "false", + "post.logout.redirect.uris" : "+", + "oauth2.device.authorization.grant.enabled" : "false", + "backchannel.logout.revoke.offline.tokens" : "false", + "saml.server.signature.keyinfo.ext" : "false", + "use.refresh.tokens" : "true", + "oidc.ciba.grant.enabled" : "false", + "backchannel.logout.session.required" : "true", + "client_credentials.use_refresh_token" : "false", + "require.pushed.authorization.requests" : "false", + "saml.client.signature" : "false", + "saml.allow.ecp.flow" : "false", + "id.token.as.detached.signature" : "false", + "saml.assertion.signature" : "false", + "client.secret.creation.time" : "1657055472", + "saml.encrypt" : "false", + "saml.server.signature" : "false", + "exclude.session.state.from.auth.response" : "false", + "saml.artifact.binding" : "false", + "saml_force_name_id_format" : "false", + "acr.loa.map" : "{}", + "tls.client.certificate.bound.access.tokens" : "false", + "saml.authnstatement" : "false", + "display.on.consent.screen" : "false", + "token.response.type.bearer.lower-case" : "false", + "saml.onetimeuse.condition" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : -1, + "protocolMappers" : [ { + "id" : "abfc756f-fc57-45b4-8a40-0cd0f8081f0c", + "name" : "Client ID", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientId", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientId", + "jsonType.label" : "String" + } + }, { + "id" : "c05d38b7-9b4d-4286-b40c-f48b3cca42e3", + "name" : "Client Host", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientHost", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientHost", + "jsonType.label" : "String" + } + }, { + "id" : "b27d0bd8-b8d9-43cb-a07a-3ec4bdc818dc", + "name" : "Client IP Address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientAddress", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientAddress", + "jsonType.label" : "String" + } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ], + "authorizationSettings" : { + "allowRemoteResourceManagement" : true, + "policyEnforcementMode" : "ENFORCING", + "resources" : [ { + "name" : "Default Resource", + "type" : "urn:withAuth:resources:default", + "ownerManagedAccess" : false, + "attributes" : { }, + "_id" : "c882ad40-c15d-4f88-ad60-c2ea2f486ce2", + "uris" : [ "/*" ] + } ], + "policies" : [ { + "id" : "b8b338bc-884d-43cf-96d8-3776f2b220f3", + "name" : "Default Policy", + "description" : "A policy that grants access only for users within this realm", + "type" : "role", + "logic" : "POSITIVE", + "decisionStrategy" : "AFFIRMATIVE", + "config" : { + "roles" : "[{\"id\":\"spiffworkflow-backend/repeat-form-role-2\",\"required\":false}]" + } + }, { + "id" : "4f5afa22-0fdf-4ed7-97b9-35400591bf6f", + "name" : "Default Permission", + "description" : "A permission that applies to the default resource type", + "type" : "resource", + "logic" : "POSITIVE", + "decisionStrategy" : "UNANIMOUS", + "config" : { + "defaultResourceType" : "urn:withAuth:resources:default", + "applyPolicies" : "[\"Default Policy\"]" + } + } ], + "scopes" : [ ], + "decisionStrategy" : "UNANIMOUS" + } + } ], + "clientScopes" : [ { + "id" : "fa3d9944-cf66-4af9-b931-1f3b02943e5b", + "name" : "acr", + "description" : "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "12ad0a69-d414-4b5b-9f5f-b647db5f8959", + "name" : "acr loa level", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-acr-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "access.token.claim" : "true", + "userinfo.token.claim" : "true" + } + } ] + }, { + "id" : "4e69d058-1229-4704-9411-decf25da0a49", + "name" : "profile", + "description" : "OpenID Connect built-in scope: profile", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${profileScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "d0d7334e-3f11-45d2-9670-46dbc1977cb2", + "name" : "full name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-full-name-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "access.token.claim" : "true", + "userinfo.token.claim" : "true" + } + }, { + "id" : "4efcf169-4df2-4cdb-b331-005aff1cee28", + "name" : "website", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "website", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "website", + "jsonType.label" : "String" + } + }, { + "id" : "3f639f2f-cf0e-4651-ab93-15a77023b5a0", + "name" : "given name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "firstName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "given_name", + "jsonType.label" : "String" + } + }, { + "id" : "16e93663-bf6a-4f6d-b5ab-8e68bf118f72", + "name" : "nickname", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "nickname", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "nickname", + "jsonType.label" : "String" + } + }, { + "id" : "b9c97283-8153-4c4d-b8d8-dd1bde17823b", + "name" : "username", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "preferred_username", + "jsonType.label" : "String" + } + }, { + "id" : "eeead6c7-1dae-4be1-9eca-988ffb38aaf4", + "name" : "zoneinfo", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "zoneinfo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "zoneinfo", + "jsonType.label" : "String" + } + }, { + "id" : "d62991bc-2583-42be-bb08-8d1527c4f162", + "name" : "family name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "lastName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "family_name", + "jsonType.label" : "String" + } + }, { + "id" : "9f761222-f84d-4a25-a53f-13e196d38a46", + "name" : "profile", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "profile", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "profile", + "jsonType.label" : "String" + } + }, { + "id" : "ec866e3c-582f-4c99-920f-d57cf03d772d", + "name" : "gender", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "gender", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "gender", + "jsonType.label" : "String" + } + }, { + "id" : "b05e679c-e00e-427e-8e47-0a4fd411c7a6", + "name" : "updated at", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "updatedAt", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "updated_at", + "jsonType.label" : "long" + } + }, { + "id" : "505ff402-5533-48ea-91f9-ab4804c3826b", + "name" : "middle name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "middleName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "middle_name", + "jsonType.label" : "String" + } + }, { + "id" : "d546af31-b669-442b-9a9d-8a6478364002", + "name" : "picture", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "picture", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "picture", + "jsonType.label" : "String" + } + }, { + "id" : "5a75c993-290f-4bfb-9044-5d7d269378b2", + "name" : "birthdate", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "birthdate", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "birthdate", + "jsonType.label" : "String" + } + }, { + "id" : "2d387240-0f2f-4f30-8464-0e7c57946743", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "2efee39d-723c-44af-9eb1-4dde9635b249", + "name" : "email", + "description" : "OpenID Connect built-in scope: email", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${emailScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "5bf7db0f-a915-43c2-bff4-475ee5c3259b", + "name" : "email", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "email", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email", + "jsonType.label" : "String" + } + }, { + "id" : "687a8c7d-c93f-47d9-a176-78b0954429c7", + "name" : "email verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "emailVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email_verified", + "jsonType.label" : "boolean" + } + } ] + }, { + "id" : "4a7737cf-83e3-40e1-b36d-9566b34e4148", + "name" : "phone", + "description" : "OpenID Connect built-in scope: phone", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${phoneScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "14bd2816-a2f3-4fde-9ac2-452dea2e9e58", + "name" : "phone number", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumber", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number", + "jsonType.label" : "String" + } + }, { + "id" : "6172e315-8999-4df8-89fa-75ffd1981793", + "name" : "phone number verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumberVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number_verified", + "jsonType.label" : "boolean" + } + } ] + }, { + "id" : "5ad0c621-d3ec-4018-98c8-d6fb630d661f", + "name" : "microprofile-jwt", + "description" : "Microprofile - JWT built-in scope", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "252fdd9f-cc91-4ca3-aaab-cdf053360e94", + "name" : "groups", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "multivalued" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "foo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "groups", + "jsonType.label" : "String" + } + }, { + "id" : "8e9b880e-6dd8-4e2f-ade2-77fc8fd0bc6d", + "name" : "upn", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "upn", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "77ca4f26-3777-451b-a907-e258f46f7b95", + "name" : "roles", + "description" : "OpenID Connect scope for add user roles to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${rolesScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "e7ebb9c0-5ed3-4c6f-bb69-22e01d26b49f", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { } + }, { + "id" : "66fd470f-419e-44cd-822e-43df8ee5fe1b", + "name" : "realm roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "foo", + "access.token.claim" : "true", + "claim.name" : "realm_access.roles", + "jsonType.label" : "String", + "multivalued" : "true" + } + }, { + "id" : "f3c313bc-7da7-4cf6-a0df-b62e77209b7c", + "name" : "client roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-client-role-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "foo", + "access.token.claim" : "true", + "claim.name" : "resource_access.${client_id}.roles", + "jsonType.label" : "String", + "multivalued" : "true" + } + } ] + }, { + "id" : "3e9849f5-15ff-43c6-b929-40f26fda2c05", + "name" : "offline_access", + "description" : "OpenID Connect built-in scope: offline_access", + "protocol" : "openid-connect", + "attributes" : { + "consent.screen.text" : "${offlineAccessScopeConsentText}", + "display.on.consent.screen" : "true" + } + }, { + "id" : "ffda6ea6-8add-4c7e-9754-66d00c6735a1", + "name" : "web-origins", + "description" : "OpenID Connect scope for add allowed web origins to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false", + "consent.screen.text" : "" + }, + "protocolMappers" : [ { + "id" : "05635d42-8bb3-440b-b871-b64c97f524da", + "name" : "allowed web origins", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-allowed-origins-mapper", + "consentRequired" : false, + "config" : { } + } ] + }, { + "id" : "6f56ae2b-253f-40f7-ba99-e8c5bbc71423", + "name" : "role_list", + "description" : "SAML role list", + "protocol" : "saml", + "attributes" : { + "consent.screen.text" : "${samlRoleListScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "7036c17a-9306-4481-82a1-d8d9d77077e5", + "name" : "role list", + "protocol" : "saml", + "protocolMapper" : "saml-role-list-mapper", + "consentRequired" : false, + "config" : { + "single" : "false", + "attribute.nameformat" : "Basic", + "attribute.name" : "Role" + } + } ] + }, { + "id" : "ce4493c0-ccb4-45f9-a46e-a40cc3f6d4b2", + "name" : "address", + "description" : "OpenID Connect built-in scope: address", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${addressScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "8a0d3248-d231-40b2-9b8e-3d63bd5a5d12", + "name" : "address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-address-mapper", + "consentRequired" : false, + "config" : { + "user.attribute.formatted" : "formatted", + "user.attribute.country" : "country", + "user.attribute.postal_code" : "postal_code", + "userinfo.token.claim" : "true", + "user.attribute.street" : "street", + "id.token.claim" : "true", + "user.attribute.region" : "region", + "access.token.claim" : "true", + "user.attribute.locality" : "locality" + } + } ] + } ], + "defaultDefaultClientScopes" : [ "email", "profile", "role_list", "roles", "acr", "web-origins" ], + "defaultOptionalClientScopes" : [ "offline_access", "phone", "microprofile-jwt", "address" ], + "browserSecurityHeaders" : { + "contentSecurityPolicyReportOnly" : "", + "xContentTypeOptions" : "nosniff", + "xRobotsTag" : "none", + "xFrameOptions" : "SAMEORIGIN", + "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection" : "1; mode=block", + "strictTransportSecurity" : "max-age=31536000; includeSubDomains" + }, + "smtpServer" : { }, + "eventsEnabled" : false, + "eventsListeners" : [ "jboss-logging" ], + "enabledEventTypes" : [ ], + "adminEventsEnabled" : false, + "adminEventsDetailsEnabled" : false, + "identityProviders" : [ ], + "identityProviderMappers" : [ ], + "components" : { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { + "id" : "b8617465-1c84-4a5f-a16f-a6f10f0f66b1", + "name" : "Trusted Hosts", + "providerId" : "trusted-hosts", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "host-sending-registration-request-must-match" : [ "true" ], + "client-uris-must-match" : [ "true" ] + } + }, { + "id" : "6061713a-c1f5-46e1-adfb-762b8768976a", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper" ] + } + }, { + "id" : "d68e938d-dde6-47d9-bdc8-8e8523eb08cd", + "name" : "Max Clients Limit", + "providerId" : "max-clients", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "max-clients" : [ "200" ] + } + }, { + "id" : "1209fa5d-37df-4f9a-b4fa-4a3cd94e21fe", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "saml-role-list-mapper", "oidc-address-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper" ] + } + }, { + "id" : "3854361d-3fe5-47fb-9417-a99592e3dc5c", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "4c4076ec-68ed-46c1-b0a5-3c8ed08dd4f6", + "name" : "Consent Required", + "providerId" : "consent-required", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "bbbe2ea2-2a36-494b-b57f-8b202740ebf4", + "name" : "Full Scope Disabled", + "providerId" : "scope", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "41eef3e1-bf71-4e8a-b729-fea8eb16b5d8", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + } ], + "org.keycloak.userprofile.UserProfileProvider" : [ { + "id" : "576f8c6a-00e6-45dd-a63d-614100fb2cc4", + "providerId" : "declarative-user-profile", + "subComponents" : { }, + "config" : { } + } ], + "org.keycloak.keys.KeyProvider" : [ { + "id" : "1f9958a4-b3ac-4a1b-af95-fd8e6053864a", + "name" : "hmac-generated", + "providerId" : "hmac-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "4e99c641-0494-49d5-979f-45cb5126f6f1" ], + "secret" : [ "4wV4voiQmFajEegv83Ugd8DxFoy3JpN4YzO5qMx4XfB7Abq8NKU4Az5AkSpxYBSdb5GJEQypA4aLmnaDyCWLIw" ], + "priority" : [ "100" ], + "algorithm" : [ "HS256" ] + } + }, { + "id" : "70fe0720-f3b7-47b4-a625-ae8fb6635da1", + "name" : "aes-generated", + "providerId" : "aes-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "76118b54-fc74-4149-9028-fab1fdc07860" ], + "secret" : [ "DvxTn0KA4TEUPqSFBw8qAw" ], + "priority" : [ "100" ] + } + }, { + "id" : "a12fdd97-1d72-4d9e-9e6a-f9e0b5d4e5f0", + "name" : "rsa-generated", + "providerId" : "rsa-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEpAIBAAKCAQEAimbfmG2pL3qesWhUrQayRyYBbRFE0Ul5Ii/AW8Kq6Kad9R2n2sT2BvXWnsWBH6KuINUFJz3Tb+gWy235Jy0Idmekwx63JR20//ZJ7dyQ+b1iadmYPpqyixGL7NrVxQYT0AEGLcD/Fwsh869F3jgfQt7N15q2arRnOrW5NMwi+IvtHxZRZ3UluxShut2577ef8cakwCv4zoTV29y+Z3XhtlKZ4WOCuqIHL3SRHwNkb+k8cY0Gwc88FHl/ihFR0fX/lc7W2AHRd98ex8il4kBFfShBZur8ZLE7QWQdXRY2EYYr3D/W6/5wf/R2fAvbVmGzcYGZ2qm6d+K1XH8VU3X84wIDAQABAoIBABXXrHwa+nOCz57CD3MLNoGiDuGOsySwisyJartQmraC7TTtDDurkASDMe72zq0WeJK368tIp6DmqQpL/eFf6xD8xHUC2PajnJg033AJuluftvNroupmcb0e9M1ZsBkbH29Zagc4iUmyuRYDWGx8wPpFvYjEYvuuIwiR+3vIp9A/0ZbcBwdtml3Of5gYTXChPj28PrA4K7oFib2Zu1aYCBEdF8h9bKRF/UlvyWeSajjddexSQ6gkEjzAEMpliCDbOGSFGwNu1pY7FF4EpyJbalzdpn44m5v9bqfS9/CDrIOOUus88Nn5wCD2OAmAQnWn0Hnh7at4A5fw3VBUmEt70ckCgYEAx0Fg8Gp3SuMaytrf9HJHJcltyDRsdSxysF1ZvDV9cDUsD28QOa/wFJRVsABxqElU+W6QEc20NMgOHVyPFed5UhQA6WfmydzGIcF5C6T5IbE/5Uk3ptGuPdI0aR7rlRfefQOnUBr28dz5UDBTb93t9+Klxcss+nLGRbugnFBAtTUCgYEAsdD+92nuF/GfET97vbHxtJ6+epHddttWlsa5PVeVOZBE/LUsOZRxmxm4afvZGOkhUrvmA1+U0arcp9crS5+Ol2LUGh/9efqLvoBImBxLwB37VcIYLJi0EVPrhVPh+9r3vah1YMBhtapS0VtuEZOr47Yz7asBg1s1Z06l+bD1JLcCgYA+3YS9NYn/qZl5aQcBs9B4vo2RfeC+M1DYDgvS0rmJ3mzRTcQ7vyOrCoXiarFxW/mgXN69jz4M7RVu9BX83jQrzj3fZjWteKdWXRlYsCseEzNKnwgc7MjhnmGEzQmc15QNs0plfqxs8MAEKcsZX1bGP873kbvWJMIjnCf3SWaxBQKBgQCh9zt2w19jIewA+vFMbXw7SGk6Hgk6zTlG50YtkMxU/YtJIAFjhUohu8DVkNhDr35x7MLribF1dYu9ueku3ew1CokmLsNkywllAVaebw+0s9qOV9hLLuC989HQxQJPtTj54SrhcPrPTZBYME7G5dqo9PrB3oTnUDoJmoLmOABjawKBgQCeyd12ShpKYHZS4ZvE87OfXanuNfpVxhcXOqYHpQz2W0a+oUu9e78MlwTVooR4O52W/Ohch2FPEzq/1DBjJrK6PrMY8DS018BIVpQ9DS35/Ga9NtSi8DX7jTXacYPwL9n/+//U3vw0mjaoMXgCv44nYu4ro62J6wvVM98hjQmLJw==" ], + "keyUse" : [ "SIG" ], + "certificate" : [ "MIICqTCCAZECBgGBz6+bXzANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1zcGlmZndvcmtmbG93MB4XDTIyMDcwNTE4NDUwMVoXDTMyMDcwNTE4NDY0MVowGDEWMBQGA1UEAwwNc3BpZmZ3b3JrZmxvdzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIpm35htqS96nrFoVK0GskcmAW0RRNFJeSIvwFvCquimnfUdp9rE9gb11p7FgR+iriDVBSc902/oFstt+SctCHZnpMMetyUdtP/2Se3ckPm9YmnZmD6asosRi+za1cUGE9ABBi3A/xcLIfOvRd44H0Lezdeatmq0Zzq1uTTMIviL7R8WUWd1JbsUobrdue+3n/HGpMAr+M6E1dvcvmd14bZSmeFjgrqiBy90kR8DZG/pPHGNBsHPPBR5f4oRUdH1/5XO1tgB0XffHsfIpeJARX0oQWbq/GSxO0FkHV0WNhGGK9w/1uv+cH/0dnwL21Zhs3GBmdqpunfitVx/FVN1/OMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAaI7BEPZpf4MU7bMWmNgyfRTRDy5wtpyfuLPGHZ9EqtnvwwzsmlmXXsC55SLXx3wJETm+rFqeRFbo/hamlRajzzD317AUpE7nhnONTukmh6UuB8hXoWiQTD+YDYMy8kneSP4zvfm27F+TgUC4cvJSYuWVaCxFx52kxqW1hZkBzYUcfi21Qb1jRrbTbso37BxuVX+GdN015If3DPD6QnAhLPAYEFA9jiL16YeMdWHdvlXXmvriDegMUYQjFYPRh6iPzUEdG6KGHItF4AkOYBQAcoaYhfxpxofVlDdOqMZ/1c7AAbe4lR6/jYQ0CbHwdUu4dzJQe3vxr7GdxcB1ypvXPA==" ], + "priority" : [ "100" ] + } + }, { + "id" : "e16c740d-3ae2-4cc5-a68d-49d99e079672", + "name" : "rsa-enc-generated", + "providerId" : "rsa-enc-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEowIBAAKCAQEAsqGsclDQDFSTn8HS1LiiNAnTwn3CS8HXPLDYMHr/jUQ8r5eD+vQY5ICh5V5c8l8J6ydbpzffFEKam54Ypp4yzaWJZ4huYBMf4vL7xrAZ4VXBreu16BIxOrThzrJe9WmI8+Annzo62mNYZbjf4WNpZDURmxZSo7v6Czprd5O6T4N5bxr8sjRRptZR8hxtrRvJnuC0jF+dLHIO5SKR1hUVG/gbpIBqGcsLkNC9nnS6M/N5YFzUIV5JhXo3+mrR/yvw7m+oS5yRsN0raCSXVenNP05Dhsd4FOYqoXBBcdgXXbiDxed0HWB/g5dASqyMydHriddGr8FU0W8/uZmF79wxPwIDAQABAoIBAFsWCaL5Bj1jWytZYDJMO5mhcTN5gPu0ShaObo66CVl1dCRtdEUg9xh9ZxBYf7ivMZWRKjEoUj44gDHd+d/sRyeJw3jhnraqydWl5TC5V1kJq4sN6GH/9M5kscf+OGGXgNgqcsnEnYICqm6kSLTbRkBstx+H0HfhQG09StNcpuIn4MsoMZT8XmZbXRLb3FhfpuTSX3t2nbSDRfUf7LI1EDnFQen/AJAA5lOHthLCdz4Gj1vfalOFjCMYOUWmL/mCDEb38F6QJZxkyhmS/r2kM09PFLOio6z3J8C8mVeq7uao0s5xAKj5SJqx4r+TTvL5aOF8JBWm8Hz1Vcip9/MjsQECgYEA/8Hpb4RggNyn+YzTxqxtPtbLFL0YywtNT+gutmJH1gyTjfx7p3dmA/NsdIeuJmBpZfA7oDXIqfj2M9QLfC5bdKnggQzrIO3BgClI88zOIWd229Bt6D1yx92k4+9eaRwOKBPn8+u0mCk8TBv32ecMLQ9o8AKNIHeCZQjByvOrIMECgYEAss0J3TzrRuEOpnxJ9fNOeB3rNpIFrpNua+oEQI4gDbBvyT7osBKkGqfXJpUQMftr8a6uBHLHV7/Wq6/aRkRhk+aER8h01DUIWGLmbCUdkFSJZ8iObMZQvURtckhzxxhYu0Ybwn0RJg/zzR4onTRO+eL1fTnb5Id55PyPt3Pp0f8CgYEAovDOoP6MYOyzk5h1/7gwrX04ytCicBGWQtdgk0/QBn3ir+3wdcPq2Y+HREKA3/BClfBUfIBnhGqZqHFqk8YQ/CWSY4Vwc30l71neIX0UwlFhdy+2JeSoMM9z0sfYtUxrdHsiJtO/LcXvpWmYIVpC9p4/s9FcShf5mhbXKE7PcsECgYBN7qqvAH94LF4rWJ8QEZWRK1E7Ptg1KFOHu79Qt+HmtZFzwPTA0c8vQxq22V/uuSxqcf2tOK4EZDxYJtTXrbRuN5pOg2PQnrDdfXX7iw3gu8gMMVFKvgGxDSM7HbNBAy6hqcQtuD+CPI/CRrPjGUqXBkKD63UZnacWlLK7fk1a1wKBgExUaqOBKmr0vldVn66E1XzZj4F4+fV5Ggka9289pBNBRlJFD4VmIYkDkOrLimyy2cYeCkocrOvF6HMJqTcOzD50pj44OWkYFRbs6vK0S7iLSX0eR158XOR9C+uZzp1vIA4sYwW3504HVdVoIU5M8ItSgDsFjGnvHopTGu3MBWPT" ], + "keyUse" : [ "ENC" ], + "certificate" : [ "MIICqTCCAZECBgGBz6+byzANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1zcGlmZndvcmtmbG93MB4XDTIyMDcwNTE4NDUwMVoXDTMyMDcwNTE4NDY0MVowGDEWMBQGA1UEAwwNc3BpZmZ3b3JrZmxvdzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALKhrHJQ0AxUk5/B0tS4ojQJ08J9wkvB1zyw2DB6/41EPK+Xg/r0GOSAoeVeXPJfCesnW6c33xRCmpueGKaeMs2liWeIbmATH+Ly+8awGeFVwa3rtegSMTq04c6yXvVpiPPgJ586OtpjWGW43+FjaWQ1EZsWUqO7+gs6a3eTuk+DeW8a/LI0UabWUfIcba0byZ7gtIxfnSxyDuUikdYVFRv4G6SAahnLC5DQvZ50ujPzeWBc1CFeSYV6N/pq0f8r8O5vqEuckbDdK2gkl1XpzT9OQ4bHeBTmKqFwQXHYF124g8XndB1gf4OXQEqsjMnR64nXRq/BVNFvP7mZhe/cMT8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEArDDC7bYbuBg33PbUQi7P77lV7PuE9uQU1F3HqulhkARQeM/xmBdJRj9CHjj62shkI3An70tJtGBJkVAHltmvjC+A6IDO5I8IbnPkvWJFu9HwphdP/C1HXYmGPPe7yGdKpy6mdCZ+LMZP7BENhOlx9yXLDFYtcGvqZ4u3XvfsLqUsRGqZHNlhVJD13dUbI6pvbwMsb3gIxozgTIa2ySHMbHafln2UQk5jD0eOIVkaNAdlHqMHiBpPjkoVxnhAmJ/dUIAqKBvuIbCOu9N0kOQSl82LqC7CZ21JCyT86Ll3n1RTkxY5G3JzGW4dyJMOGSyVnWaQ9Z+C92ZMFcOt611M2A==" ], + "priority" : [ "100" ], + "algorithm" : [ "RSA-OAEP" ] + } + } ] + }, + "internationalizationEnabled" : false, + "supportedLocales" : [ ], + "authenticationFlows" : [ { + "id" : "ad06e38c-daaa-40cc-a649-324abb777152", + "alias" : "Account verification options", + "description" : "Method with which to verity the existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-email-verification", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Verify Existing Account by Re-authentication", + "userSetupAllowed" : false + } ] + }, { + "id" : "6b40c845-6135-40c5-b001-c869c042dd39", + "alias" : "Authentication Options", + "description" : "Authentication options.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "basic-auth", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "basic-auth-otp", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-spnego", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 30, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "598310bc-a020-4062-bef2-466eeef1452e", + "alias" : "Browser - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-otp-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "0ab61691-762f-47f2-8f72-f237c91ada96", + "alias" : "Direct Grant - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "direct-grant-validate-otp", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "37b288b0-224e-4ef4-9fb3-4199970f2f68", + "alias" : "First broker login - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-otp-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "23fdb162-467c-42bf-8f1c-1cb0fe78e010", + "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", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-confirm-link", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Account verification options", + "userSetupAllowed" : false + } ] + }, { + "id" : "8f02ecf9-fff1-4b2e-9a64-5b95e55da60d", + "alias" : "Reset - Conditional OTP", + "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-otp", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "1721679e-95cf-47e9-8d34-d6c0053f51fb", + "alias" : "User creation or linking", + "description" : "Flow for the existing/non-existing user alternatives", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "create unique user config", + "authenticator" : "idp-create-user-if-unique", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Handle Existing Account", + "userSetupAllowed" : false + } ] + }, { + "id" : "eef76ef5-3fa8-4c7e-ba20-d1a161301300", + "alias" : "Verify Existing Account by Re-authentication", + "description" : "Reauthentication of existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-username-password-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "First broker login - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "2c32428d-7a2b-485b-9a17-603cdbd8888f", + "alias" : "browser", + "description" : "browser based authentication", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-cookie", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-spnego", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "identity-provider-redirector", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 25, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 30, + "autheticatorFlow" : true, + "flowAlias" : "forms", + "userSetupAllowed" : false + } ] + }, { + "id" : "f1be3ec5-0ced-4c57-8475-12f4a6c1f365", + "alias" : "clients", + "description" : "Base authentication for clients", + "providerId" : "client-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "client-secret", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-jwt", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-secret-jwt", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 30, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-x509", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 40, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "88e11533-694e-4215-aa33-f8ce81907f4a", + "alias" : "direct grant", + "description" : "OpenID Connect Resource Owner Grant", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "direct-grant-validate-username", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "direct-grant-validate-password", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 30, + "autheticatorFlow" : true, + "flowAlias" : "Direct Grant - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "0969b892-b2ab-4a23-bd56-8218052635a6", + "alias" : "docker auth", + "description" : "Used by Docker clients to authenticate against the IDP", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "docker-http-basic-authenticator", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "9662b24c-9250-4b08-a06a-26414bee38bb", + "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", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "review profile config", + "authenticator" : "idp-review-profile", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "User creation or linking", + "userSetupAllowed" : false + } ] + }, { + "id" : "669177a0-1afc-4200-a3ad-e73e67745802", + "alias" : "forms", + "description" : "Username, password, otp and other auth forms.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-username-password-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Browser - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "69b76b57-f24c-4cb8-8f77-a700bed6b681", + "alias" : "http challenge", + "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "no-cookie-redirect", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Authentication Options", + "userSetupAllowed" : false + } ] + }, { + "id" : "c8c491a4-b7d0-4b50-9a1b-8de76fec161a", + "alias" : "registration", + "description" : "registration flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-page-form", + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : true, + "flowAlias" : "registration form", + "userSetupAllowed" : false + } ] + }, { + "id" : "6bdea6a2-d72b-445b-85a8-53a64e53d34d", + "alias" : "registration form", + "description" : "registration form", + "providerId" : "form-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-user-creation", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-profile-action", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 40, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-password-action", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 50, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-recaptcha-action", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 60, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "6d02ae51-dc2f-4d48-85de-0c510455ec04", + "alias" : "reset credentials", + "description" : "Reset credentials for a user if they forgot their password or something", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "reset-credentials-choose-user", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-credential-email", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-password", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 30, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 40, + "autheticatorFlow" : true, + "flowAlias" : "Reset - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "474c0664-e089-4a11-b73d-6425561bece2", + "alias" : "saml ecp", + "description" : "SAML ECP Profile Authentication Flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "http-basic-authenticator", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + } ], + "authenticatorConfig" : [ { + "id" : "2287b965-2eb4-45a4-b23f-79fc3a0acfce", + "alias" : "create unique user config", + "config" : { + "require.password.update.after.registration" : "false" + } + }, { + "id" : "16567f8c-11f0-4020-beb3-3b29c3b54db7", + "alias" : "review profile config", + "config" : { + "update.profile.on.first.login" : "missing" + } + } ], + "requiredActions" : [ { + "alias" : "CONFIGURE_TOTP", + "name" : "Configure OTP", + "providerId" : "CONFIGURE_TOTP", + "enabled" : true, + "defaultAction" : false, + "priority" : 10, + "config" : { } + }, { + "alias" : "terms_and_conditions", + "name" : "Terms and Conditions", + "providerId" : "terms_and_conditions", + "enabled" : false, + "defaultAction" : false, + "priority" : 20, + "config" : { } + }, { + "alias" : "UPDATE_PASSWORD", + "name" : "Update Password", + "providerId" : "UPDATE_PASSWORD", + "enabled" : true, + "defaultAction" : false, + "priority" : 30, + "config" : { } + }, { + "alias" : "UPDATE_PROFILE", + "name" : "Update Profile", + "providerId" : "UPDATE_PROFILE", + "enabled" : true, + "defaultAction" : false, + "priority" : 40, + "config" : { } + }, { + "alias" : "VERIFY_EMAIL", + "name" : "Verify Email", + "providerId" : "VERIFY_EMAIL", + "enabled" : true, + "defaultAction" : false, + "priority" : 50, + "config" : { } + }, { + "alias" : "delete_account", + "name" : "Delete Account", + "providerId" : "delete_account", + "enabled" : false, + "defaultAction" : false, + "priority" : 60, + "config" : { } + }, { + "alias" : "update_user_locale", + "name" : "Update User Locale", + "providerId" : "update_user_locale", + "enabled" : true, + "defaultAction" : false, + "priority" : 1000, + "config" : { } + } ], + "browserFlow" : "browser", + "registrationFlow" : "registration", + "directGrantFlow" : "direct grant", + "resetCredentialsFlow" : "reset credentials", + "clientAuthenticationFlow" : "clients", + "dockerAuthenticationFlow" : "docker auth", + "attributes" : { + "cibaBackchannelTokenDeliveryMode" : "poll", + "cibaAuthRequestedUserHint" : "login_hint", + "clientOfflineSessionMaxLifespan" : "0", + "oauth2DevicePollingInterval" : "5", + "clientSessionIdleTimeout" : "0", + "actionTokenGeneratedByUserLifespan-execute-actions" : "", + "actionTokenGeneratedByUserLifespan-verify-email" : "", + "clientOfflineSessionIdleTimeout" : "0", + "actionTokenGeneratedByUserLifespan-reset-credentials" : "", + "cibaInterval" : "5", + "realmReusableOtpCode" : "false", + "cibaExpiresIn" : "120", + "oauth2DeviceCodeLifespan" : "600", + "actionTokenGeneratedByUserLifespan-idp-verify-account-via-email" : "", + "parRequestUriLifespan" : "60", + "clientSessionMaxLifespan" : "0" + }, + "keycloakVersion" : "20.0.1", + "userManagedAccessAllowed" : false, + "clientProfiles" : { + "profiles" : [ ] + }, + "clientPolicies" : { + "policies" : [ ] + } +} diff --git a/keycloak/realm_exports/spiffworkflow-realm.json b/keycloak/realm_exports/spiffworkflow-realm.json index 270e4876f..78652bcf4 100644 --- a/keycloak/realm_exports/spiffworkflow-realm.json +++ b/keycloak/realm_exports/spiffworkflow-realm.json @@ -418,41 +418,44 @@ "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false, "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ], "users" : [ { - "id" : "5a97144d-4f59-4a8c-b365-463d0577a740", - "createdTimestamp" : 1669600821350, + "id" : "26b0e310-ea33-4cea-8bfd-a32dc6bc11d4", + "createdTimestamp" : 1676302139599, "username" : "admin", "enabled" : true, "totp" : false, "emailVerified" : false, - "firstName" : "", - "lastName" : "", "email" : "admin@spiffworkflow.org", "credentials" : [ { - "id" : "ef435043-ef0c-407a-af5b-ced13182a408", + "id" : "644ff652-31d1-4349-9340-ce3b5fb76b5c", "type" : "password", - "userLabel" : "My password", - "createdDate" : 1669600831704, - "secretData" : "{\"value\":\"4D4JRvE7kR5nfGiIdrwzK+0drmy3kX++TlT1BTvYix8N83c9FGTPWvxR1Hl4ggEKuCCAEYZnTzVJZY0DcUcN+A==\",\"salt\":\"yI7UkD+mCuq0H35AnNV/KA==\",\"additionalParameters\":{}}", + "createdDate" : 1676302139645, + "secretData" : "{\"value\":\"P6nrEJgmgdL+HbNA9tPkOyHYaLAqLg6cXh27ACgVQiOox4qwNE8Iv1L4ssispV4gsmuHiY+alio/2UMuyMGvEw==\",\"salt\":\"g214ckcAyig59U/3Oqwq4w==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], "requiredActions" : [ ], "realmRoles" : [ "default-roles-spiffworkflow" ], + "clientRoles" : { + "realm-management" : [ "realm-admin" ] + }, "notBefore" : 0, "groups" : [ ] }, { - "id" : "4048e9a7-8afa-4e69-9904-389657221abe", - "createdTimestamp" : 1665517741516, + "id" : "06fbd6ec-8ef8-431e-92f9-a981025a21de", + "createdTimestamp" : 1675718483674, "username" : "alex", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "alex@sartography.com", + "attributes" : { + "spiffworkflow-employeeid" : [ "111" ] + }, "credentials" : [ { - "id" : "81a61a3b-228d-42b3-b39a-f62d8e7f57ca", + "id" : "04ddcd24-741e-4dbc-815f-ecd9d5dc3266", "type" : "password", - "createdDate" : 1665517748308, - "secretData" : "{\"value\":\"13OdXlB1S1EqHL+3/0y4LYp/LGCn0UW8/Wh9ykgpUbRrwdX6dY3iiMlKePfTy5nXoH/ISmPlxNKOe5z7FWXsgg==\",\"salt\":\"pv0SEb7Ctk5tpu2y32L2kw==\",\"additionalParameters\":{}}", + "createdDate" : 1675718483717, + "secretData" : "{\"value\":\"3Gpq5mVzKq+rZRNalSZbQFiwVKBLH5CnFKScnP27xfxUMPCxLZRqDHc99BZC4AG9t7dixG3LOT5WMcHFplzEDA==\",\"salt\":\"PGN51PkpenHIKgEYE+7XPQ==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -461,18 +464,41 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "b4dc5a30-4bd7-44fc-88b5-839fbb8567ea", - "createdTimestamp" : 1665518311550, + "id" : "4fca2b7a-ac1e-4088-9fd9-0656e1b01d8f", + "createdTimestamp" : 1676302139770, "username" : "amir", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "amir@status.im", "credentials" : [ { - "id" : "e589f3ad-bf7b-4756-89f7-7894c03c2831", + "id" : "b7869251-8c8e-4479-a532-1d7650d6365b", "type" : "password", - "createdDate" : 1665518319210, - "secretData" : "{\"value\":\"mamd7Hi6nV5suylSrUgwWon3Gw3WeOIvAJu9g39Mq1iYoXWj2rI870bGHiSITLaFBpdjLOEmlu9feKkULOXNpQ==\",\"salt\":\"wG7tkMQfPKRW9ymu4ekujQ==\",\"additionalParameters\":{}}", + "createdDate" : 1676302139804, + "secretData" : "{\"value\":\"3aUGyNNCI/U5DgwpKsLxkyJW+Jfk2sUHO4fVHNs/2ppz5O15z4SFNkCHR2e4uRm9ZAMS3puyXNggDLIlrhtBzw==\",\"salt\":\"S0nZfiVxxUe0F7fMDpnEHA==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "27b5bdce-1c02-4249-b8ba-521f9bcae2d3", + "createdTimestamp" : 1676302139921, + "username" : "app.program.lead", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "app.program.lead@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "121" ] + }, + "credentials" : [ { + "id" : "8cd62c66-7357-4c8f-ae57-e45a10150f2d", + "type" : "password", + "createdDate" : 1676302139956, + "secretData" : "{\"value\":\"NhRRaTaL4o8TLmLgFrfIlLo1lBGRgAcoQ+ct7ypw/osYNXcF1zIC7i0AYrwrSSWQ60Wxcx6RZTFRQsZobwCbUw==\",\"salt\":\"nOhBgYVO/Me08wmfOatRdQ==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -506,21 +532,21 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "d58b61cc-a77e-488f-a427-05f4e0572e20", - "createdTimestamp" : 1669132945413, + "id" : "6151b58a-ca4f-44e6-a82a-f13363234555", + "createdTimestamp" : 1676302140070, "username" : "core", "enabled" : true, "totp" : false, "emailVerified" : false, - "firstName" : "", - "lastName" : "", "email" : "core@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "113" ] + }, "credentials" : [ { - "id" : "ee80092b-8ee6-4699-8492-566e088b48f5", + "id" : "4efdee1e-0874-4cf7-a5c8-2af0c79fcfb2", "type" : "password", - "userLabel" : "My password", - "createdDate" : 1669132955862, - "secretData" : "{\"value\":\"x0f/IvOAsMmbQzgc1LXJ9O7dDepeFURi7lD4Wy0NZBrFRyQ3pMXM6FHNNjhVDeZMsTr2tesYYQ2BK3z9xIPPrA==\",\"salt\":\"vx4/Z41MiUnLqaVt+vMmOQ==\",\"additionalParameters\":{}}", + "createdDate" : 1676302140103, + "secretData" : "{\"value\":\"Zv7x1cugXlVz6obLPCZhMYjvt0KigYglyPHjhpmLJSjnqKvVHCe1pGXY/ldt8Uo7gnN4g/++p0sU7zmH6bpasA==\",\"salt\":\"9M480GmtU4YBGdv7useKbQ==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -529,18 +555,136 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "99e7e4ea-d4ae-4944-bd31-873dac7b004c", - "createdTimestamp" : 1665517024483, + "id" : "0bc23c31-47d3-4112-89b9-e43eb1cb0038", + "createdTimestamp" : 1676302140217, + "username" : "core1.contributor", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "core1.contributor@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "155" ] + }, + "credentials" : [ { + "id" : "97cdefc8-9df7-4936-a5db-418827131f5e", + "type" : "password", + "createdDate" : 1676302140251, + "secretData" : "{\"value\":\"oCVxd48zaQ4cMkhtLbURMiQqC8ukvbW198eHzYDtauQL/vHh2YtGdedLrXwgy0WI7esakDbG8Iu1M4U/KScOlA==\",\"salt\":\"pmC02eAqJ3uv62lsEq8luw==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "3b81b45e-759b-4d7a-aa90-adf7b447208c", + "createdTimestamp" : 1676302140358, + "username" : "core2.contributor", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "core2.contributor@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "156" ] + }, + "credentials" : [ { + "id" : "3a1c0044-d80e-4c06-92e6-48dbc6f14008", + "type" : "password", + "createdDate" : 1676302140392, + "secretData" : "{\"value\":\"Kfm1GKzzlSlZaKfB9VZlHcYLK9tB+v72wMjpcsei6QSLmMZm/Qip8i03CZ1Y70GYwqqVzdjU/C7f08IZbmkEwQ==\",\"salt\":\"vOD5MN6OHKaOWvEELdJAcQ==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "8143c52a-6de9-43c4-80db-4a87c901530a", + "createdTimestamp" : 1676302140496, + "username" : "core3.contributor", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "core3.contributor@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "157" ] + }, + "credentials" : [ { + "id" : "e9a9dcac-e93b-4818-9382-ef57de3f6998", + "type" : "password", + "createdDate" : 1676302140530, + "secretData" : "{\"value\":\"92YIJdDsBtm5c11PILNiI/B7Dwym/uymMuQsX6FiJ+n4/cS9wYUVkMzsR8qIU/dNxuWe9pTOxJVgiVLkeNl4rg==\",\"salt\":\"NeYpcejK+bCTpQM5Bpw1qw==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "3170e294-ced9-475c-8cef-c37cb9cb1388", + "createdTimestamp" : 1676302140649, + "username" : "core4.contributor", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "core4.contributor@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "158" ] + }, + "credentials" : [ { + "id" : "fb7c308a-f5eb-4018-91ca-77efce2f5653", + "type" : "password", + "createdDate" : 1676302140687, + "secretData" : "{\"value\":\"qTN5OKjH8atQQrHapczP05FNJ+tDWJK/NyfKGaBh4pwKXLHeATmLxN54GeIow6jDhqQA9y7R/QcuQIXHDTXY8A==\",\"salt\":\"ZHI5LtxZZZShHFWO2bWIuw==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "fd398c8d-aada-46ce-a035-8d90335a5c33", + "createdTimestamp" : 1676302140818, + "username" : "core5.contributor", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "core5.contributor@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "159" ] + }, + "credentials" : [ { + "id" : "3ff62cf7-eb9e-4205-b1b7-7d32c35eedd6", + "type" : "password", + "createdDate" : 1676302140854, + "secretData" : "{\"value\":\"4lFuRCdMia8hwnkIzV16/M9qA2aqU6sXtHqqXoQ+Tvs4BACUezToDkKV+5Tq9AStenJTyY5AYtV7rUl+q/o8Hw==\",\"salt\":\"UO1gHgSeFiZr1iC836LSmQ==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "7b9767ac-24dc-43b0-838f-29e16b4fd14e", + "createdTimestamp" : 1675718483773, "username" : "dan", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "dan@sartography.com", + "attributes" : { + "spiffworkflow-employeeid" : [ "115" ] + }, "credentials" : [ { - "id" : "d517c520-f500-4542-80e5-7144daef1e32", + "id" : "8bc911c7-02fa-43fd-8e61-a313721ffc89", "type" : "password", - "createdDate" : 1665517033429, - "secretData" : "{\"value\":\"rgWPI1YobMfDaaT3di2+af3gHU8bkreRElAHgYFA+dXHw0skiGVd1t57kNLEP49M6zKYjZzlOKr0qvAxQF0oSg==\",\"salt\":\"usMZebZnPYXhD6ID95bizg==\",\"additionalParameters\":{}}", + "createdDate" : 1675718483819, + "secretData" : "{\"value\":\"pQ/vKJoOG0sNGeNsjm+kVVnGImIjhLMBTjw1lRXj3X5ffW22EzXF7+kYrTBgXnTmFUql2INVpIl838vYmg80RQ==\",\"salt\":\"a0zK/X/EO3VhXUr8Z3P1uA==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -549,18 +693,18 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "1834a79d-917f-4e4c-ab38-8ec376179fe9", - "createdTimestamp" : 1665517805115, + "id" : "f567ec03-a98c-48bf-8bc4-126b3614f9b2", + "createdTimestamp" : 1675718483878, "username" : "daniel", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "daniel@sartography.com", "credentials" : [ { - "id" : "f240495c-265b-42fc-99db-46928580d07d", + "id" : "c6eaa80d-a7a5-4cf5-b1ae-a5c11c03ad25", "type" : "password", - "createdDate" : 1665517812636, - "secretData" : "{\"value\":\"sRCF3tFOZrUbEW220cVHhQ7e89iKqjgAMyO0BaYCPZZw1tEjZ+drGj+bfwRbuuK0Nps3t//YGVELsejRogWkcw==\",\"salt\":\"XQtLR9oZctkyRTi2Be+Z0g==\",\"additionalParameters\":{}}", + "createdDate" : 1675718483930, + "secretData" : "{\"value\":\"7MQz+KX6UlxONyNJffBsR5ARE88jjna6Hxd1+WJbBp2XWk/ozFCWKk+KhcAih0i21LLCSBqHdZPxGCUErgn7FA==\",\"salt\":\"fAwQQbHLynQ6s+DYNJ8xJA==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -569,18 +713,78 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "72d32cba-e2e2-489d-9141-4d94e3bb2cda", - "createdTimestamp" : 1665517787787, + "id" : "8020118a-b6db-4b02-ac85-1b61768b4766", + "createdTimestamp" : 1676302140961, + "username" : "dao.project.lead", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "dao.project.lead@status.im", + "credentials" : [ { + "id" : "6c18b235-2ba3-4cfa-9aa4-a0a82f9e653e", + "type" : "password", + "createdDate" : 1676302140995, + "secretData" : "{\"value\":\"+Ad8q+y/1krN63dVy9ynROYGR/uHBF0fuCrEnjUx6k+0Tl92C2If5RSzv1GtsKzH7o4riU5xQIZKURewoocu1g==\",\"salt\":\"+gcwdTYByCUVyySbE1z06g==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "a12635e9-084c-4724-aa5b-327fd23c262e", + "createdTimestamp" : 1676302141100, + "username" : "desktop.program.lead", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "desktop.program.lead@status.im", + "credentials" : [ { + "id" : "0a59934d-1991-4887-9018-1264b5e81e8f", + "type" : "password", + "createdDate" : 1676302141136, + "secretData" : "{\"value\":\"L3S4fkxdMk7o2B52aPW/gr5EW/8M0IL7l3214MwSlHLUdccrzaObqkCrbZlk/FhEbP1iuWeGPxXhufS+WGdxxA==\",\"salt\":\"wt/gWUDTmtpugOqFiRX17w==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "a71e29a7-678c-4a08-9273-5c8490577c98", + "createdTimestamp" : 1676302141251, + "username" : "desktop.project.lead", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "desktop.project.lead@status.im", + "credentials" : [ { + "id" : "1b5939c9-ae17-4288-966e-216803c0692f", + "type" : "password", + "createdDate" : 1676302141287, + "secretData" : "{\"value\":\"Jz6ZticAS12Jwtmpo3FFMC28G5HSr1hpUxHZK7UYtYMSLta0gyPoKLloCKONAxfeJRmiX2VqAfQrx4plefM7yA==\",\"salt\":\"kDWqLNKW1CUV8TncWe8jmg==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "3873c0ba-349c-4bec-8be2-5ced8acd56ec", + "createdTimestamp" : 1675718483992, "username" : "elizabeth", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "elizabeth@sartography.com", "credentials" : [ { - "id" : "ae951ec8-9fc9-4f1b-b340-bbbe463ae5c2", + "id" : "13dd277b-b5e4-4ff7-aba8-2d648858224e", "type" : "password", - "createdDate" : 1665517794484, - "secretData" : "{\"value\":\"oudGUsbh8utUavZ8OmoUvggCYxr+RHCgwcqpub5AgbITsK4DgY01X0SlDGRTdNGOIqoHse8zGBNmcyBNPWjC0w==\",\"salt\":\"auHilaAS2Lo7oa0UaA7L6A==\",\"additionalParameters\":{}}", + "createdDate" : 1675718484034, + "secretData" : "{\"value\":\"qN84NNHkapbSOpYDUnEqemMFUiGJSbCdyUfsPJyinbzFWltqnrmgAQ/9j5dJweyJS2uXTEQgOFcV83LmqmIT4Q==\",\"salt\":\"A+gRdmehei+Ob6wNe/cszA==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -589,64 +793,21 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "faf29027-dc54-4804-a408-4989a8c9c243", - "createdTimestamp" : 1669132994561, + "id" : "4ec4e65d-18f8-4ee1-ad52-45caa0d221dd", + "createdTimestamp" : 1676302141388, "username" : "fin", "enabled" : true, "totp" : false, "emailVerified" : false, - "firstName" : "", - "lastName" : "", "email" : "fin@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "118" ] + }, "credentials" : [ { - "id" : "2379940c-98b4-481a-b629-0bd1a4e91acf", + "id" : "73d159aa-5c5c-4424-8b27-e045da019e9e", "type" : "password", - "userLabel" : "My password", - "createdDate" : 1669133003955, - "secretData" : "{\"value\":\"Wb9XtkrxJ9YdW7faHcWgQ+WK3JqBYCQ5wTn9rJa7Uo47I2TrniH+7/CBODIaiF3ipYAEZBkiCJDnPqg2qbZ+aA==\",\"salt\":\"bY1gRb+5sjbmrYWvxfl9CQ==\",\"additionalParameters\":{}}", - "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" - } ], - "disableableCredentialTypes" : [ ], - "requiredActions" : [ ], - "realmRoles" : [ "default-roles-spiffworkflow" ], - "notBefore" : 0, - "groups" : [ ] - }, { - "id" : "13e009b2-e96f-43b7-a227-465675ece81d", - "createdTimestamp" : 1669303701625, - "username" : "fin1", - "enabled" : true, - "totp" : false, - "emailVerified" : false, - "firstName" : "", - "lastName" : "", - "email" : "fin1@status.im", - "credentials" : [ { - "id" : "96216746-ff72-454e-8288-232428d10b42", - "type" : "password", - "userLabel" : "My password", - "createdDate" : 1669303725352, - "secretData" : "{\"value\":\"ukPIO1rlfpzbxb+FXHAwCdNQ4cq3yX+Ke11uFPpGy7xBNT5UgLzO3oIK34Cw1Ma3+gFqK6/OsT4Q5fZd/AsVJQ==\",\"salt\":\"iSIY1gAdz7wkAwnGer95Lw==\",\"additionalParameters\":{}}", - "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" - } ], - "disableableCredentialTypes" : [ ], - "requiredActions" : [ ], - "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\":{}}", + "createdDate" : 1676302141423, + "secretData" : "{\"value\":\"s9q7zRTromg6hXz9IkDHHvXu/wea9SxVPVLmgMhtGgdD/k0yqSe4VTylIWl54NNJKaenSpLc+3OLWzToAV47sA==\",\"salt\":\"BDEO5r3cors4b/dXXfJT7A==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -675,18 +836,18 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "9b46f3be-a81d-4b76-92e6-2ac8462f5ec8", - "createdTimestamp" : 1665688255982, + "id" : "92d09dda-4c61-4978-bf06-1599dceb4f03", + "createdTimestamp" : 1676302141663, "username" : "finance_user1", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "finance_user1@status.im", "credentials" : [ { - "id" : "f14722ec-13a7-4d35-a4ec-0475d405ae58", + "id" : "b271460e-a319-47ad-864d-ee213c6fd18f", "type" : "password", - "createdDate" : 1665688275943, - "secretData" : "{\"value\":\"PlNhf8ShIvaSP3CUwCwAJ2tkqcTCVmCWUy4rbuLSXxEIiuGMu4XeZdsrE82R8PWuDQhlWn/YOUOk38xKZS2ySQ==\",\"salt\":\"m7JGY2cWgFBXMYQSSP2JQQ==\",\"additionalParameters\":{}}", + "createdDate" : 1676302141698, + "secretData" : "{\"value\":\"6uC9Lukr74pZjpdiYCdRd9xSKQ3i84HbuSdnltqV2XQYe3JvfdRaH3GYJvIYQ5Agl1MKtIcsjIfBlmTzOku7Dg==\",\"salt\":\"TUjWsZg82XiXYINQ8fYhRA==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -695,18 +856,21 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "087bdc16-e362-4340-aa60-1ff71a45f844", - "createdTimestamp" : 1665516884829, + "id" : "98f7b174-40a9-4717-a193-fbe76f3ad127", + "createdTimestamp" : 1676302141803, "username" : "harmeet", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "harmeet@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "109" ] + }, "credentials" : [ { - "id" : "89c26090-9bd3-46ac-b038-883d02e3f125", + "id" : "cccc5afd-b23f-4fce-a6b0-abc8792332e7", "type" : "password", - "createdDate" : 1665516905862, - "secretData" : "{\"value\":\"vDzTFQhjg8l8XgQ/YFYZSMLxQovFc/wflVBiRtAk/UWRKhJwuz3XInFbQ64wbYppBlXDYSmYis3luKv6YyUWjQ==\",\"salt\":\"58OQLETS0sM9VpXWoNa6rQ==\",\"additionalParameters\":{}}", + "createdDate" : 1676302141841, + "secretData" : "{\"value\":\"ObAc50+abMGNm9Z31J2ob8eNryIgj8Q2NeB+ATRM+kEW9MN30ippK81NYVAKDSVAp7fFTbzLMJvAieT2UNfQQQ==\",\"salt\":\"m9vXAf8tVuCkMRGyMqoUHw==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -715,18 +879,44 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "f55135de-7341-459d-8a42-a59f52d05bed", - "createdTimestamp" : 1674148694958, + "id" : "4f3fadc8-f0a3-45fb-8710-c054385b866b", + "createdTimestamp" : 1676302141941, + "username" : "infra.project-lead", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "infra.project-lead@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "130" ] + }, + "credentials" : [ { + "id" : "e422f671-1693-4469-8cdc-0ea7dcb27c66", + "type" : "password", + "createdDate" : 1676302141975, + "secretData" : "{\"value\":\"gWFNRdQhmsN2IMyaZEHgTk8A0mna72VYfeWk7PX31MhBQjQIGsctuEKK3TNxiB046LM8ZiUntA59sTPBgouVeQ==\",\"salt\":\"AtU0bmAz1z4f7wh/Z/ru1Q==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "a5af0724-2711-4829-a422-6fec294e76f8", + "createdTimestamp" : 1676302142081, "username" : "infra.sme", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "infra.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "119" ] + }, "credentials" : [ { - "id" : "e1f4368c-ed7c-481c-9426-fc0b8f2bf520", + "id" : "e3c326ee-a998-408c-97a6-5b928bf6da41", "type" : "password", - "createdDate" : 1674148695008, - "secretData" : "{\"value\":\"7RHwvrhGAA3EddNNjPaVah+EOg5be0eugiwLLQLGlhFGSdGfg6kiUmPr5wBqBabivXHiSZgv/BiaL5KQ/VmR+A==\",\"salt\":\"HW3yCxErwpKASPvHX8o9Uw==\",\"additionalParameters\":{}}", + "createdDate" : 1676302142117, + "secretData" : "{\"value\":\"pLxJuJDfX6vdnO1HahlteExuTUUpkFuAbwxg8TH90EFGQs+MGmQhryoiKRI2Q8SeimwddBYLcEH5s7Ta/UekLA==\",\"salt\":\"L/InLQaRzvEw2Xrz2NK42g==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -735,21 +925,87 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "1561518b-c327-491e-9db3-23c2b5394104", - "createdTimestamp" : 1669303773974, + "id" : "eafc96dc-1504-4b63-9706-019726fd8a44", + "createdTimestamp" : 1676302142224, + "username" : "infra1.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "infra1.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "131" ] + }, + "credentials" : [ { + "id" : "948d20a6-a832-43da-adbf-04c042cc3d69", + "type" : "password", + "createdDate" : 1676302142258, + "secretData" : "{\"value\":\"6jH+rotKwSZJVEbrWJZMEtqCkonWUeURMSC/RvWPpMoo2u8alobTup7YO/3XfsporaggRkdTYyfC8gAN966xHA==\",\"salt\":\"MvbL0CKytxAn/z8VDjhfKA==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "da2f48ff-6b7f-47bb-b5b3-efd47ae09e9a", + "createdTimestamp" : 1676302142376, + "username" : "infra2.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "infra2.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "132" ] + }, + "credentials" : [ { + "id" : "c4392d26-8d6e-43c5-b7cc-38440b2b4146", + "type" : "password", + "createdDate" : 1676302142410, + "secretData" : "{\"value\":\"tyRW38f5f8QVicL4ZyU0Jh7pH0/hBKX201PoHeb8YgUEBP1PkqfZf4/OpnrB3VvilGDHqcni8AAfmu2f8dhLxg==\",\"salt\":\"+Cgz7NFi1bJlBCqcuv6UKA==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "6c8829ab-d37c-4638-99b0-c83e732dc02f", + "createdTimestamp" : 1676566095383, + "username" : "infra3.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "infra3.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "167" ] + }, + "credentials" : [ { + "id" : "06476e91-a1db-4f9c-848b-f9ba120a200e", + "type" : "password", + "createdDate" : 1676566095417, + "secretData" : "{\"value\":\"00UdICckafKEytSulbqdURfya9ZO4UlmAlQQ6R/he44Jv0wkYGIk/vadNE5ACgmIBunoj6jANVbu87ZWNxp1Dw==\",\"salt\":\"etUtwyB9nvChOvyw1P0xkA==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "b8d0d90e-9a7e-446c-9984-082cb315af8f", + "createdTimestamp" : 1675718484095, "username" : "j", "enabled" : true, "totp" : false, "emailVerified" : false, - "firstName" : "", - "lastName" : "", - "email" : "j@status.im", + "email" : "j@sartography.com", "credentials" : [ { - "id" : "e71ec785-9133-4b7d-8015-1978379af0bb", + "id" : "723958a6-2c82-4642-ab61-c2c22b10e8d1", "type" : "password", - "userLabel" : "My password", - "createdDate" : 1669303786522, - "secretData" : "{\"value\":\"g/nsCceqGWoU7thzq21RFSNUB8WP6l9/x2ghKFAKC1Xrqcf2At+u0r8GglqM6WmLthOTtrwICs98tS4ZPLmsbA==\",\"salt\":\"Na/OfJ9itENgaLPsIntzUQ==\",\"additionalParameters\":{}}", + "createdDate" : 1675718484139, + "secretData" : "{\"value\":\"FJ4/Ma8AeoWT+T3ky3Xj/t+zZ+1RwU3EyW6PcULp92rFoRneIysaRWjWGkA/k/EbAca9uIA1NHXD7heonrkgew==\",\"salt\":\"AQgPybRGxF/pB4GvjUtpOg==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -758,18 +1014,18 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "13f5481e-c6b5-450d-8aaf-e13c1c1f5914", - "createdTimestamp" : 1665518332327, + "id" : "01ccfba1-7f7f-4164-8e98-efd2794af5f2", + "createdTimestamp" : 1676302142505, "username" : "jakub", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "jakub@status.im", "credentials" : [ { - "id" : "ce141fa5-b8d5-4bbe-93e7-22e7119f97c2", + "id" : "336bf45f-cd87-40b2-9a3a-d66be16cf477", "type" : "password", - "createdDate" : 1665518338651, - "secretData" : "{\"value\":\"+L4TmIGURzFtyRMFyKbPmQ8iYSC639K0GLNHXM+T/cLiMGxVr/wvWj5j435c1V9P+kwO2CnGtd09IsSN8cXuXg==\",\"salt\":\"a2eNeYyoci5fpkPJJy735g==\",\"additionalParameters\":{}}", + "createdDate" : 1676302142548, + "secretData" : "{\"value\":\"pVJrP4BNkRXMsdP36WZMw7F/yEzdDSIyTfn/LinHxCKAX4kWUEVL6Emt8QMLbGEynYyZXmYwwYsvrEbZApf4Zw==\",\"salt\":\"vfoJY+NlFfnNXJyIKNlMXg==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -778,18 +1034,18 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "3965a6c8-31df-474f-9a45-c268ed98e3fd", - "createdTimestamp" : 1665518284693, + "id" : "2df44301-506a-4053-9ece-830d2b3c295b", + "createdTimestamp" : 1676302142640, "username" : "jarrad", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "jarrad@status.im", "credentials" : [ { - "id" : "113e0343-1069-476d-83f9-21d98edb9cfa", + "id" : "bb7f1376-3cb0-4b1b-adf4-6c2d6dc3ced8", "type" : "password", - "createdDate" : 1665518292234, - "secretData" : "{\"value\":\"1CeBMYC3yiJ/cmIxHs/bSea3kxItLNnaIkPNRk2HefZiCdfUKcJ/QLI0O9QO108G2Lzg9McR33EB72zbFAfYUw==\",\"salt\":\"2kWgItvYvzJkgJU9ICWMAw==\",\"additionalParameters\":{}}", + "createdDate" : 1676302142675, + "secretData" : "{\"value\":\"SFFDsvpTOhT3IsmY6MXEjYjEYjEAR5kCBEiHVNW3Qmm8USdQUIHFyIELIv7ZaEWJFaS9j7hvP9Wo0n0AKsFeQw==\",\"salt\":\"VlHEqjvYfDeciX2IJvJQ3w==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -798,18 +1054,18 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "58bcce19-41ec-4ae7-b930-b37be7ad4ba3", - "createdTimestamp" : 1665516949583, + "id" : "06f69a51-780c-4d3b-9c32-2c93d01d1e28", + "createdTimestamp" : 1675718484199, "username" : "jason", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "jason@sartography.com", "credentials" : [ { - "id" : "40abf32e-f0cc-4a17-8231-1a69a02c1b0b", + "id" : "f2330ab2-30ad-483c-af05-190a839bba21", "type" : "password", - "createdDate" : 1665516957192, - "secretData" : "{\"value\":\"nCnRYH5rLRMu1E7C260SowAdvJfQCSdf4LigcIzSkoPwT+qfLT5ut5m99zakNLeHLoCtGhO2lSVGUQWhdCUYJw==\",\"salt\":\"mW5QN/RSr55I04VI6FTERA==\",\"additionalParameters\":{}}", + "createdDate" : 1675718484243, + "secretData" : "{\"value\":\"M/HQLqkHOWMCCnUg6Qd5pPdag6apDosVMkPTm+mDbbNa36mwkEvOmVYD48OSwwruUYiMV3dKByBBx8/QZqqbsA==\",\"salt\":\"R1V9v/uSxAXrS0o4Gh9wcw==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -818,18 +1074,18 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "29c11638-3b32-4024-8594-91c8b09e713c", - "createdTimestamp" : 1665518366585, + "id" : "0333aaa7-cfe8-4dd2-a8c7-cbefc9ea9c8e", + "createdTimestamp" : 1675718484299, "username" : "jon", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "jon@sartography.com", "credentials" : [ { - "id" : "8b520e01-5b9b-44ab-9ee8-505bd0831a45", + "id" : "9dfd7471-8b2a-422f-a1c4-cd2d17f2eebe", "type" : "password", - "createdDate" : 1665518373016, - "secretData" : "{\"value\":\"lZBDnz49zW6EkT2t7JSQjOzBlYhjhkw3hHefcOC4tmet+h/dAuxSGRuLibJHBap2j6G9Z2SoRqtyS8bwGbR42g==\",\"salt\":\"MI90jmxbLAno0g5O4BCeHw==\",\"additionalParameters\":{}}", + "createdDate" : 1675718484347, + "secretData" : "{\"value\":\"wIKYqLU64kVmqRixyS6ctMv3WrP8ADHGY0uIlV+T03Q6Um8jWvxFeyxK+jczQip9/Fe3cnyO3ofDo3IZNeNSEg==\",\"salt\":\"dS4upVR1o9fhRF/Doz/KaA==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -838,18 +1094,18 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "af15c167-d0e7-4a41-ac2c-109188dd7166", - "createdTimestamp" : 1665516966482, + "id" : "2ed7cd7d-0529-48d2-a819-c4cec99afeca", + "createdTimestamp" : 1675718484404, "username" : "kb", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "kb@sartography.com", "credentials" : [ { - "id" : "2c0be363-038f-48f1-86d6-91fdd28657cf", + "id" : "0532ba60-239b-4537-9506-be8dd9b7c608", "type" : "password", - "createdDate" : 1665516982394, - "secretData" : "{\"value\":\"yvliX8Mn+lgpxfMpkjfsV8CASgghEgPA2P1/DR1GP5LSFoGwGCEwj0SmeQAo+MQjBsn3nfvtL9asQvmIYdNZwQ==\",\"salt\":\"kFr1K94QCEx9eGD25rZR9g==\",\"additionalParameters\":{}}", + "createdDate" : 1675718484447, + "secretData" : "{\"value\":\"0zDVcRHBgnX6hNrnJMXhF5/I8QD1QzZWW/aAVtcI1FamcnsjYlArUd4AOamzTRi9NHhK71uPry79cVevUlffNg==\",\"salt\":\"985YMqQx41KSSGtU5l4EVQ==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -858,21 +1114,41 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "23c464ea-6a98-462c-a8b9-e8e561804361", - "createdTimestamp" : 1669132970114, + "id" : "cdec7198-19f5-4788-aceb-e8c68f4c277f", + "createdTimestamp" : 1675718484460, + "username" : "kevin", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "kevin@sartography.com", + "credentials" : [ { + "id" : "c1729585-5811-4b56-976c-c3370d1386f5", + "type" : "password", + "createdDate" : 1675718484506, + "secretData" : "{\"value\":\"bUeoB4qNIQe3nbBytEw269xMmYO+/8rq0GnwNVgwjiEHfeya2t3g+mu3yg0ZmahxUgdh1iTfx9Ja6VGDtGk7Ug==\",\"salt\":\"fbm81DCMYdMXF+NB/92OBw==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "fa70eed9-7241-44d6-b858-bb4b21b3d988", + "createdTimestamp" : 1676302142767, "username" : "lead", "enabled" : true, "totp" : false, "emailVerified" : false, - "firstName" : "", - "lastName" : "", "email" : "lead@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "114" ] + }, "credentials" : [ { - "id" : "96e836a4-1a84-45c5-a9ed-651b0c90195e", + "id" : "e1f56434-a2df-4f71-9d2a-a544396fc70e", "type" : "password", - "userLabel" : "My password", - "createdDate" : 1669132979516, - "secretData" : "{\"value\":\"DsOkyXBHcwY0HAGta+m+E5jXDZwxGl/fgROCR7ph23oJ3j9833UVH5VLHfYcZ3YZixUIfskYMlcwW91uqO0oxQ==\",\"salt\":\"zOLZMvNnOIEB0t32DghWiQ==\",\"additionalParameters\":{}}", + "createdDate" : 1676302142800, + "secretData" : "{\"value\":\"G1LVPQEY7X3LkSjMWXUjAjBGtfS+QOneNZldp4uNSy8ZqCaQDyB31VKmvcvjfo+0PS8jUZVqy49UPy3kjiJlyw==\",\"salt\":\"BRvKMf/vAelH8EHWHZhcSA==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -881,21 +1157,21 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "fef2c863-be05-49f2-94d0-702238505a4d", - "createdTimestamp" : 1669303745591, - "username" : "lead1", + "id" : "6e9129f9-34f8-43bb-953b-de4156d425ba", + "createdTimestamp" : 1676302142894, + "username" : "legal.project-lead", "enabled" : true, "totp" : false, "emailVerified" : false, - "firstName" : "", - "lastName" : "", - "email" : "lead1@status.im", + "email" : "legal.project-lead@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "133" ] + }, "credentials" : [ { - "id" : "4e17388b-6c44-44e1-b20a-a873c0feb9a8", + "id" : "b17d488c-7665-40d4-b758-c392ecc9e793", "type" : "password", - "userLabel" : "My password", - "createdDate" : 1669303762736, - "secretData" : "{\"value\":\"NNPFZcVk47adUPH1q3L27uPkULy9OocZkOzi4qUVvO+tvZJVH5sMrSUYqM8S71AqdHNZD1a8ge6amF6k6dDIkQ==\",\"salt\":\"7e48fZJBAeVferVYA4gNVw==\",\"additionalParameters\":{}}", + "createdDate" : 1676302142929, + "secretData" : "{\"value\":\"FiEmNY1c+4xOepA3lzOzzaaNgthk9rMz1xXiV+5F2DUwBtoEqFRrlGTdHVVz5XjrcFhgW15+R3rSEfHsCLJTiA==\",\"salt\":\"xYYuuodywbhxqXcj3XMqKw==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -904,38 +1180,21 @@ "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, + "id" : "d6fab16b-c345-4ee0-8f72-d7d821c0cf96", + "createdTimestamp" : 1676302143022, "username" : "legal.sme", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "legal.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "125" ] + }, "credentials" : [ { - "id" : "52fd8bd4-8fc4-4b71-8325-424220ef83af", + "id" : "c4e9edd8-d202-4417-b784-cf3a68984fd9", "type" : "password", - "createdDate" : 1674148695076, - "secretData" : "{\"value\":\"Rce1M5ph1ITsCguiHlv7YMcDTyofRnSPnOraQskkmeojV+tlUeBBsHV1fTiqJ4f13vE1qtnwC/60vQV8BprsHw==\",\"salt\":\"zFyJq5G2F/pZeLmgKaGoxQ==\",\"additionalParameters\":{}}", + "createdDate" : 1676302143055, + "secretData" : "{\"value\":\"90MXzzni35vPq0xTGAB+/fSFo+yAFIvoCkuviBceJu6swoFncL/UFyG5nefMK5NhjOc4cmBikG/UtGX7kNcb5Q==\",\"salt\":\"jpo2kLvh9TwmCnIhGpZ3Uw==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -944,18 +1203,113 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "6f5bfa09-7494-4a2f-b871-cf327048cac7", - "createdTimestamp" : 1665517010600, + "id" : "41d034bd-bc29-44ce-8fb4-fdf386869c18", + "createdTimestamp" : 1676302143149, + "username" : "legal1.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "legal1.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "134" ] + }, + "credentials" : [ { + "id" : "083bf762-7474-4e17-be3f-7ea7e6f4a5f0", + "type" : "password", + "createdDate" : 1676302143182, + "secretData" : "{\"value\":\"itxTYUYjdtpJx3+5zD+T3WZZZ0H6XTnDADpMoEOPmsff3d4FI4N2X/Nq9rs446/P/cGZjMOxSJPpQAAHZA2B8Q==\",\"salt\":\"FpsMWSZGjg3uvogWTmwYMw==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "8763cdfb-46d4-4585-a17f-57acc1e44646", + "createdTimestamp" : 1676566095195, + "username" : "legal2.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "legal2.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "165" ] + }, + "credentials" : [ { + "id" : "9322a6c5-0c19-48ee-aa92-c28eae605e95", + "type" : "password", + "createdDate" : 1676566095260, + "secretData" : "{\"value\":\"yfqeGYoyN5ZZM7SoAbVvDCM/J3fwhS17A1/L1GkLZoB3+844lK5g7iWJjrnrmBpzNAPjKKDx0aTGdEWetxt9Qg==\",\"salt\":\"zvh/FXb9F/wdWUupHwNFjw==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "adba601b-d3c0-43fc-ae7e-cb6120ab342d", + "createdTimestamp" : 1676566095313, + "username" : "legal3.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "legal3.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "166" ] + }, + "credentials" : [ { + "id" : "d1bb52f8-92b1-4873-a356-e9dc9739e1e6", + "type" : "password", + "createdDate" : 1676566095348, + "secretData" : "{\"value\":\"END4w4oxI1H5C5l4dqeYqrClb0y+vx3tuI484ELpqouEIol5P/piTiv8Q5/ECbb3jj8opjUFZZfvc12VIukCWw==\",\"salt\":\"e0EvbNYHC9jdqPkX3AneYw==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "588e69b9-7534-4073-861d-500475b12b24", + "createdTimestamp" : 1675718484566, + "username" : "madhurya", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "madhurya@sartography.com", + "attributes" : { + "spiffworkflow-employeeid" : [ "160" ] + }, + "credentials" : [ { + "id" : "cab9ffca-62c4-4f23-a0e0-2868c0b6ca9f", + "type" : "password", + "createdDate" : 1675718484612, + "secretData" : "{\"value\":\"fcYbol1qijp7CnrKvcodRf0S6WITpBYSKkXLo7qGlRfpwwLzDOHnSQCCTUwq3C6iQRyi4X92vhoS/InDQQG5cw==\",\"salt\":\"dcgX0EenciihfrTM2zTaRg==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "f600aecb-4d83-43ec-9b02-90d58ec377cd", + "createdTimestamp" : 1676302143277, "username" : "manuchehr", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "manuchehr@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "110" ] + }, "credentials" : [ { - "id" : "07dabf55-b5d3-4f98-abba-3334086ecf5e", + "id" : "6c558363-cc87-42b5-9bf7-894abd87f2db", "type" : "password", - "createdDate" : 1665517017682, - "secretData" : "{\"value\":\"1btDXHraz9l0Gp4g1xxdcuZffLsuKsW0tHwQGzoEtTlI/iZdrKPG9WFlCEFd84qtpdYPJD/tvzn6ZK6zU4/GlQ==\",\"salt\":\"jHtMiO+4jMv9GqLhC9wg4w==\",\"additionalParameters\":{}}", + "createdDate" : 1676302143310, + "secretData" : "{\"value\":\"7wfnqRDKijqetmNMW+WbQd79mJM7kADp79fO+VGKsTavCtx7Cr0xHaP7+nQMtjVZVNxgVbRt8G8EQzln+ucGsg==\",\"salt\":\"GAJvSLr0KJYWquqgr/xd2A==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -964,18 +1318,18 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "d1c46b47-67c4-4d07-9cf4-6b1ceac88fc1", - "createdTimestamp" : 1665517760255, + "id" : "058b60f8-799e-48b0-a2b7-2e65e7a35724", + "createdTimestamp" : 1675718484672, "username" : "mike", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "mike@sartography.com", "credentials" : [ { - "id" : "1ed375fb-0f1a-4c2a-9243-2477242cf7bd", + "id" : "669f5421-843d-411d-9f24-1be41e545e52", "type" : "password", - "createdDate" : 1665517768715, - "secretData" : "{\"value\":\"S1cxZ3dgNB+A6yfMchDWEGP8OyZaaAOU/IUKn+QWFt255yoFqs28pfmwCsevdzuh0YfygO9GBgBv7qZQ2pknNQ==\",\"salt\":\"i+Q9zEHNxfi8TAHw17Dv6w==\",\"additionalParameters\":{}}", + "createdDate" : 1675718484715, + "secretData" : "{\"value\":\"YILRiRdrsy8CA716ZQazpQOf7mpiXGaYnR26ra3pSjmHkZS9tsePTRwU2OIGPwbN1LKJcIzrpfEP7cVW2Lm17w==\",\"salt\":\"7mfD1X7Hns/5pPgHb9uZ1Q==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -984,20 +1338,18 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "cecacfd3-2f59-4ce2-87d9-bea91ef13c5b", - "createdTimestamp" : 1666102618518, + "id" : "9d23748e-23a7-4c48-956c-64da75871277", + "createdTimestamp" : 1675718484779, "username" : "natalia", "enabled" : true, "totp" : false, - "emailVerified" : true, - "firstName" : "", - "lastName" : "", + "emailVerified" : false, "email" : "natalia@sartography.com", "credentials" : [ { - "id" : "b6aa9936-39cc-4931-bfeb-60e6753de5ba", + "id" : "476024e5-62e4-48b6-afbb-cc2834fae4c7", "type" : "password", - "createdDate" : 1666102626704, - "secretData" : "{\"value\":\"kGyQIqZM6n9rjGZkNScJbkFjLvRJ2I+ZzCtjQ80e+zX7QaXtIF3CEeSY6KTXVjE8Z74oyVBWTIibpiTblm5Ztw==\",\"salt\":\"0k+Y+QJiW0YhxuxxYigasg==\",\"additionalParameters\":{}}", + "createdDate" : 1675718484823, + "secretData" : "{\"value\":\"FfrpgES+XI2w4NRe1aBmolPFcERbEUDXZcFtUWucrbhBspQLYNaN2VLmeDRV0VcT47Bn8dqjU11ct64WDtffWA==\",\"salt\":\"7rZd3fqY54i1eoNyXCcZ1w==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -1006,18 +1358,21 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "c3ea06ee-c497-48e6-8816-43c8ef68bd8b", - "createdTimestamp" : 1674148694747, - "username" : "program.lead", + "id" : "df72b3d2-07fd-4cb0-a447-a1c433db49d5", + "createdTimestamp" : 1676302143785, + "username" : "peopleops.partner", "enabled" : true, "totp" : false, "emailVerified" : false, - "email" : "program.lead@status.im", + "email" : "peopleops.partner@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "150" ] + }, "credentials" : [ { - "id" : "393e3cd9-c403-41dd-8562-7edba6acedd3", + "id" : "f5f3e98b-cd5b-4ffe-91e7-995f1c20ce44", "type" : "password", - "createdDate" : 1674148694793, - "secretData" : "{\"value\":\"AD/rFDJcnQNVSZLVnLl6FzdiMSkRFiKiF2L6jyPtnAOAuQ6IivNvDIqiZf98rPuSq1zs8wjeDzFzyXvTYp7Pjg==\",\"salt\":\"T4XlF58M6LNTX8ksxYq8jQ==\",\"additionalParameters\":{}}", + "createdDate" : 1676302143819, + "secretData" : "{\"value\":\"szOx+rvCLcUv1wFEkBH+AJY4Hx9WKrF3taH+ewG3Hf0vbca+hqPHt31uqcmjsm5XqJimWOyJMbVXssQjegdeQw==\",\"salt\":\"GgPD9/K0PPFnWjHpQQtlcg==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -1026,18 +1381,343 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "f3852a7d-8adf-494f-b39d-96ad4c899ee5", - "createdTimestamp" : 1665516926300, + "id" : "69697a8c-00b4-485a-a651-e19824c60936", + "createdTimestamp" : 1676302143531, + "username" : "peopleops.partner.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "peopleops.partner.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "148" ] + }, + "credentials" : [ { + "id" : "4b6703e0-00a8-4635-8766-8ed5070ed051", + "type" : "password", + "createdDate" : 1676302143565, + "secretData" : "{\"value\":\"/Las6VWB1spJGIwUuVQkoEAUmWO7/NjujPuM9sHfcsOR/GGeAA8lM4j1mj2w0LGTIsGLjFqqb/B7lD2TQQd/Ww==\",\"salt\":\"0qFMVOcWrlnjtoNxhOAfgQ==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "d97fc1ad-86c4-4c21-918a-2462bd8e3051", + "createdTimestamp" : 1676302143658, + "username" : "peopleops.partner1.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "peopleops.partner1.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "149" ] + }, + "credentials" : [ { + "id" : "af4de7eb-35e2-4a00-9af8-1ef15f078c7d", + "type" : "password", + "createdDate" : 1676302143692, + "secretData" : "{\"value\":\"93L2IJMLlOlfIoIAZULNgGH7gseLoDOYWbHlZvUHR1K+YkZIlrHcAw8qj5TV6YMQ2RMhrr7FmTLpxUUUMH4xRA==\",\"salt\":\"lFh+hNL2QziKf+YVyH56wg==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "2a5d7caa-2c3e-4404-a133-ec220c0307db", + "createdTimestamp" : 1676566095780, + "username" : "peopleops.partner2.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "peopleops.partner2.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "173" ] + }, + "credentials" : [ { + "id" : "64fc835c-b693-4fed-ab9f-952cbaadbbfd", + "type" : "password", + "createdDate" : 1676566095815, + "secretData" : "{\"value\":\"w5nUlwlH1Z46WGhfejPIiRW6OkE9bcjHNCVySUDzMIpkbCm3f78XfuvdGSDeCpJ/FQCJuFo5ciDJ7ExXLyLfnQ==\",\"salt\":\"nz1xSxci+NFsyPZPhFDtZQ==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "2df3aa5e-5e5b-4c4a-b9bc-3a916c651632", + "createdTimestamp" : 1676566095846, + "username" : "peopleops.partner3.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "peopleops.partner3.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "174" ] + }, + "credentials" : [ { + "id" : "efaaec98-45c7-45cc-b4a4-32708882b72f", + "type" : "password", + "createdDate" : 1676566095880, + "secretData" : "{\"value\":\"B9M+AGxXUX4/+ce0y6AgFBm4F7phl5+6zToumcfheXglqcag2jr7iqLTtvwVkz3w8x7rmxUrzs7rkJPhK+/Jpg==\",\"salt\":\"rLFkhDJLxRuCNw7PNswlSQ==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "dbf941e7-0b45-4bc6-ae9e-d7153d32ce47", + "createdTimestamp" : 1676302143401, + "username" : "peopleops.project-lead", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "peopleops.project-lead@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "147" ] + }, + "credentials" : [ { + "id" : "85fa4e0a-2f59-4c51-8e8b-20acb9813ab9", + "type" : "password", + "createdDate" : 1676302143434, + "secretData" : "{\"value\":\"FBi/INvDb50hA4QNRcSbd5gc10Dspq7QppiCvQ6ualnH/MlTyVq5CL9o1BWya0xxVdG/4jxFkUlgpN1w5liZ1Q==\",\"salt\":\"s2yJeI/k96iSy8zHAdTVSQ==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "8fcc32c3-a59b-4027-940b-b7b7bbf93df2", + "createdTimestamp" : 1676302144161, + "username" : "peopleops.talent", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "peopleops.talent@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "141" ] + }, + "credentials" : [ { + "id" : "74305e87-15c4-480a-84c9-5088216188f9", + "type" : "password", + "createdDate" : 1676302144195, + "secretData" : "{\"value\":\"U6irNGF/8ZJka3gjteQAmBdjWZM5bQhcfVzsWI5yVFF8NapEsz0hmKorNcwQwA1QKGI4KbEHQNLWN/6I4HgqPg==\",\"salt\":\"9cavEE9W+z4gwXnIE34ekg==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "b5d73c3f-9f3c-4150-b138-c0091e3e4eeb", + "createdTimestamp" : 1676302143912, + "username" : "peopleops.talent.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "peopleops.talent.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "143" ] + }, + "credentials" : [ { + "id" : "6135fee1-5b71-416a-9148-e3c5a19670b5", + "type" : "password", + "createdDate" : 1676302143945, + "secretData" : "{\"value\":\"9QdaH1x6CSa7LQ+hKw1Qgl5F+Md8vTsvGJkz8JCTMUa7lyJ8neCVDnsyfPpUsDVhwHjXTJKU2pfG7J+EmulvuQ==\",\"salt\":\"4ZGCY+mwe3u/S7hwvDIu7Q==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "9de57a58-189e-4026-b1d5-9342a14cbae7", + "createdTimestamp" : 1676302144028, + "username" : "peopleops.talent1.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "peopleops.talent1.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "142" ] + }, + "credentials" : [ { + "id" : "9d755c05-8375-493a-84e8-dbc049045419", + "type" : "password", + "createdDate" : 1676302144061, + "secretData" : "{\"value\":\"Isqg2v+L8JrDih2kaNXI8W7Tx/gAeE9C0ADlzbeegnGtSp9NpjogUpw8uEMhiAcewFiJ5VB8jv0FUolrWDzUxg==\",\"salt\":\"6wsq6XUIACyDagGZwwPE0w==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "22f26b09-0e38-487c-9578-e3768a5693cb", + "createdTimestamp" : 1676302144678, + "username" : "ppg.ba", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "ppg.ba@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "127" ] + }, + "credentials" : [ { + "id" : "50abf76f-46c5-4494-8805-477bfb0cff39", + "type" : "password", + "createdDate" : 1676302144712, + "secretData" : "{\"value\":\"oRQLaV/yKMKsROaBgpENGBJtBpVvei3DQVJPjsk+84iw3HfwS6Q1Q4lkQDNhC8eusnE9QkFg0Ra8Ymkk7Ja+bw==\",\"salt\":\"4oI/XDnS1NFSHKIIWTYUIQ==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "4c327a1e-8075-46de-9d9d-db98012c4002", + "createdTimestamp" : 1676302144292, + "username" : "ppg.ba.project-lead", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "ppg.ba.project-lead@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "137" ] + }, + "credentials" : [ { + "id" : "c8d6147e-868a-4ad0-a770-d3cb59127f5d", + "type" : "password", + "createdDate" : 1676302144326, + "secretData" : "{\"value\":\"m/yI4W4Hfh/zqkYdVv0q6/hzGloeqv02BaV1xfRwymPULNwnIZgvhA+35PYfgdYyuQ/7HzbZMERUXJDDWN+rQg==\",\"salt\":\"pm9wVgFwft4QJGG+6h1IWA==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "2002b429-686e-40c9-a79e-c9d189c2f279", + "createdTimestamp" : 1676302144546, + "username" : "ppg.ba.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "ppg.ba.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "138" ] + }, + "credentials" : [ { + "id" : "95c2479e-bb8a-4af3-b71e-17128983ffce", + "type" : "password", + "createdDate" : 1676302144580, + "secretData" : "{\"value\":\"n6I1XJn8qfa9laWUVk0NsmNrB8wvWDFotWxtTEEK/LaP5L6UerSBN3+u6TwPCte0AJrFzl7tYoLjqYcxl/cKRw==\",\"salt\":\"N+/8B05vhtUJFQaKvg+SYQ==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "2cc27223-369b-4abb-b7b3-7c3668bb4695", + "createdTimestamp" : 1676566095589, + "username" : "ppg.ba1.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "ppg.ba1.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "170" ] + }, + "credentials" : [ { + "id" : "80015df9-1c37-4c2c-9862-e4c5bf3c7fe1", + "type" : "password", + "createdDate" : 1676566095623, + "secretData" : "{\"value\":\"aHhv9WD2OpLT99Pt8adXov9qlO+mHdZc/YnLcwmg/FN1GZ5s1ExKD+PgiJnbUMyiIrEoTaMImRlG0+CaXNB8pA==\",\"salt\":\"WG3QARMAE6XD4CYMq/vVog==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "ccdd9a3c-2df1-4b01-8cd0-f983e2975044", + "createdTimestamp" : 1676566095652, + "username" : "ppg.ba2.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "ppg.ba2.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "171" ] + }, + "credentials" : [ { + "id" : "1a1b635b-78a0-4e1b-be27-54fa8e5bf46e", + "type" : "password", + "createdDate" : 1676566095686, + "secretData" : "{\"value\":\"lvIpCEkCU7VjWkc5HVjIpbEX3m2y0qRAm6vpUOF6jsC3kPOU32kGTpXtoAXRMQYqzwwrZPezkWiBWSc9tZQZmw==\",\"salt\":\"4vtZJjWkwRZZpQHL0y2cFQ==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "6d570a0f-66dc-4059-a9b5-17bcfaf92c25", + "createdTimestamp" : 1676566095715, + "username" : "ppg.ba3.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "ppg.ba3.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "172" ] + }, + "credentials" : [ { + "id" : "81737a3e-74be-48e7-8540-47df7189f6b8", + "type" : "password", + "createdDate" : 1676566095750, + "secretData" : "{\"value\":\"92827vUG05pG+5KqIU0x3YP8KzAygyflfN7ClS+87JOuSvQjElY8yaLtUNftZn2nr2EK/ud1HHfVPdjNHqv3lQ==\",\"salt\":\"ggPrdGdcE+U8spc6rzMAow==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "f56fe387-d153-42c2-880a-6726bd624bae", + "createdTimestamp" : 1676302144802, "username" : "sasha", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "sasha@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "112" ] + }, "credentials" : [ { - "id" : "4a170af4-6f0c-4e7b-b70c-e674edf619df", + "id" : "4363c0b5-a81b-4540-9c4a-1e09642200f3", "type" : "password", - "createdDate" : 1665516934662, - "secretData" : "{\"value\":\"/cimS+PL6p+YnOCF9ZSA6UuwmmLZ7aVUZUthiFDqp/sn0c8GTpWmAdDIbJy2Ut+D4Rx605kRFQaekzRgSYPxcg==\",\"salt\":\"0dmUnLfqK745YHVSz6HOZg==\",\"additionalParameters\":{}}", + "createdDate" : 1676302144835, + "secretData" : "{\"value\":\"HXN4xHOzCiY2bU5KJHeEdVxLMEJuRlr1YTddwHwnyssJNNvkpu8Xf6odCyKaoqmG2398Jug6xEGsK80AtiaRwQ==\",\"salt\":\"/tX12irRtDSLuDhVsFEyBg==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -1046,18 +1726,44 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "74374cda-1516-48e5-9ef2-1fd7bcee84d3", - "createdTimestamp" : 1674148695088, + "id" : "c85c76fb-2912-4ffa-bab5-55bfc1c300ff", + "createdTimestamp" : 1676302144924, + "username" : "security.project-lead", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "security.project-lead@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "151" ] + }, + "credentials" : [ { + "id" : "2bb621d1-4257-4490-9da1-57261b7f4b38", + "type" : "password", + "createdDate" : 1676302144959, + "secretData" : "{\"value\":\"MGxW4Og2jnK1IC7FSf7AOPxc0GNenf5atmHjd+IShdS+9UvyAZzSCqPKkgOTw96ZHYC9AJqaUnKMKHk3Coq9/A==\",\"salt\":\"95koAVaw1PCSHuvpQ4vbqA==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "f21ea0bd-1207-4266-86cc-75291f5ede45", + "createdTimestamp" : 1676302145049, "username" : "security.sme", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "security.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "123" ] + }, "credentials" : [ { - "id" : "43427e80-292e-453f-9968-511a1064729e", + "id" : "8daeefb0-826e-46bd-9c23-1d635a22ab05", "type" : "password", - "createdDate" : 1674148695133, - "secretData" : "{\"value\":\"HB68S1rm/fef2nY2qpakAyZ0a+OFM0G/Xp+kHNdTQSWZA6fYq8EUzhfTFkUQ5xuTriOesXao0srtFmcCs2Pi8Q==\",\"salt\":\"e8J1O8M7mrDq/jTJXzwYyQ==\",\"additionalParameters\":{}}", + "createdDate" : 1676302145082, + "secretData" : "{\"value\":\"kmXDFDqBcrR6EvQ5Qb+rsgjLVxVzM9eocBLc7M2MWobksYH3Wj7/2E8Oho1CmIVCpNEJT2GF7k2Kg5BvM9+mqw==\",\"salt\":\"qJzL1IU8qzv28fnC3AIOiw==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -1066,13 +1772,81 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "487d3a85-89dd-4839-957a-c3f6d70551f6", - "createdTimestamp" : 1657115173081, + "id" : "3a9f7b4d-c872-4da6-a6fc-6cdb44ec19df", + "createdTimestamp" : 1676302145172, + "username" : "security1.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "security1.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "135" ] + }, + "credentials" : [ { + "id" : "3a6d8e50-11f0-434d-8ada-6773af4e1779", + "type" : "password", + "createdDate" : 1676302145205, + "secretData" : "{\"value\":\"YTAV7zHTS38W1W/YVF4UZPqoe0EBs5DRR49gAj7sxPJe/7XCfy0VI0587yByOrvG4ouDtgKVWPM3zhChbEL8UQ==\",\"salt\":\"E9AfHFACJtt+jWrLXelgwg==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "7cf99174-49f1-4036-9eff-f7ba111a691f", + "createdTimestamp" : 1676566095455, + "username" : "security2.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "security2.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "168" ] + }, + "credentials" : [ { + "id" : "2402ab6b-c06f-4db6-a2ab-e2a0d63c7082", + "type" : "password", + "createdDate" : 1676566095491, + "secretData" : "{\"value\":\"SKxvUtsnbbqUMfcNnIU9YnrsrfCE7MH801Mf50pL9rj5/k+ZIrB2nDowGVjip0wdIgiYZbdT7mwHjmc2KBrmoQ==\",\"salt\":\"Ww6KCOsMjQmMkEAP0Pabfg==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "01daff17-0ead-4ca1-ae90-9da59ac2878d", + "createdTimestamp" : 1676566095522, + "username" : "security3.sme", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "security3.sme@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "169" ] + }, + "credentials" : [ { + "id" : "99ccf7fb-a8a5-44c1-82a8-074af6f1a21d", + "type" : "password", + "createdDate" : 1676566095557, + "secretData" : "{\"value\":\"LBBgnnqfxU+NqlT33rPCk2IyDrQQs9wdTG0syZ2GyovKe3iwBmarBio+0kSKiWWZQmF085ZO3jeR82hc1TDv3A==\",\"salt\":\"T6qwoJLQaXdaPBZZvhVCvw==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "b768e3ef-f905-4493-976c-bc3408c04bec", + "createdTimestamp" : 1675447832524, "username" : "service-account-spiffworkflow-backend", "enabled" : true, "totp" : false, "emailVerified" : false, - "email" : "service-account@status.im", "serviceAccountClientId" : "spiffworkflow-backend", "credentials" : [ ], "disableableCredentialTypes" : [ ], @@ -1084,13 +1858,12 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "22de68b1-4b06-4bc2-8da6-0c577e7e62ad", - "createdTimestamp" : 1657055472800, + "id" : "b6fb214b-cb8a-4403-9308-ac6d4e13ef26", + "createdTimestamp" : 1675447832560, "username" : "service-account-withauth", "enabled" : true, "totp" : false, "emailVerified" : false, - "email" : "service-account-withauth@status.im", "serviceAccountClientId" : "withAuth", "credentials" : [ ], "disableableCredentialTypes" : [ ], @@ -1102,18 +1875,67 @@ "notBefore" : 0, "groups" : [ ] }, { - "id" : "3d45bb85-0a2d-4b15-8a19-d26a5619d359", - "createdTimestamp" : 1674148694810, + "id" : "e1c9fd76-ba96-4136-8b30-332ee3eb0140", + "createdTimestamp" : 1676302145293, "username" : "services.lead", "enabled" : true, "totp" : false, "emailVerified" : false, "email" : "services.lead@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "122" ] + }, "credentials" : [ { - "id" : "45607c53-3768-4f76-bda3-4d31b39ffccd", + "id" : "a3ec77b6-259c-4334-a7fc-648045667774", "type" : "password", - "createdDate" : 1674148694884, - "secretData" : "{\"value\":\"E3GPcOLU56efhBQE7MMZa0OM0FAtgK5kDA9sy65uCwSyaoZGp4ZVUDsIfIkWe+TEEQA5QP5FVJbJhwvdkx3m9w==\",\"salt\":\"dySpiEZxeyb11oQZR2WYVQ==\",\"additionalParameters\":{}}", + "createdDate" : 1676302145327, + "secretData" : "{\"value\":\"Tc/U2FhuJie4U7svQdSzThoT0ZPTvYT+HPS6FmunyqiKZ0zkZrQHAidkVBNKadprxeWrTOD21cN0H+ZeCfemyw==\",\"salt\":\"5BR7mhSEZPBbuZwhMuhqrg==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "96c7c431-e65a-4f5a-93a5-e0ada7b072c1", + "createdTimestamp" : 1675711127686, + "username" : "services1.lead", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "services1.lead@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "42" ] + }, + "credentials" : [ { + "id" : "2d28c82a-cf15-4b96-a355-1ada0533fd32", + "type" : "password", + "createdDate" : 1675711127754, + "secretData" : "{\"value\":\"VmsJIj0pxHj1W2soM0E2nfR13ctGQSqUntC2voHUzMQcyLL/aqU9R+e+JunM0mtWuE3ljiHD704hcLNf4FH7uQ==\",\"salt\":\"TJGLlhTOqmFC0vz7FQNn5Q==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-spiffworkflow" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "b9451067-e227-42f9-944a-f1fb79c4a2c7", + "createdTimestamp" : 1675715650520, + "username" : "services3.lead", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "email" : "services3.lead@status.im", + "attributes" : { + "spiffworkflow-employeeid" : [ "hey1" ] + }, + "credentials" : [ { + "id" : "4a24f2d9-e030-440a-a672-3fb75322a9f3", + "type" : "password", + "createdDate" : 1675715650571, + "secretData" : "{\"value\":\"4r1zwtnm5l4JpVEdp0hwH1mRhrrGqOja6PfNFkjyWdVMhnUuN9a2FnXQjmwa3P+8Boz9HUB0Ag40UbPI9c6LIg==\",\"salt\":\"ROQEPFvg/Q4h/9OoETqh8g==\",\"additionalParameters\":{}}", "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" } ], "disableableCredentialTypes" : [ ], @@ -1186,8 +2008,12 @@ "id" : "02fa6179-9399-4bb1-970f-c4d8e8b5f99f", "clientId" : "admin-cli", "name" : "${client_admin-cli}", + "description" : "", + "rootUrl" : "", + "adminUrl" : "", + "baseUrl" : "", "surrogateAuthRequired" : false, - "enabled" : false, + "enabled" : true, "alwaysDisplayInConsole" : false, "clientAuthenticatorType" : "client-secret", "redirectUris" : [ ], @@ -1517,6 +2343,21 @@ "claim.name" : "clientId", "jsonType.label" : "String" } + }, { + "id" : "a7692d41-b905-4049-9004-f6bea690051d", + "name" : "spiffworkflow-employeeid", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "aggregate.attrs" : "false", + "userinfo.token.claim" : "true", + "multivalued" : "false", + "user.attribute" : "spiffworkflow-employeeid", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "spiffworkflow-employeeid" + } } ], "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ], @@ -2334,7 +3175,7 @@ "subType" : "authenticated", "subComponents" : { }, "config" : { - "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" ] + "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper" ] } }, { "id" : "d68e938d-dde6-47d9-bdc8-8e8523eb08cd", @@ -2352,7 +3193,7 @@ "subType" : "anonymous", "subComponents" : { }, "config" : { - "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" ] + "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper" ] } }, { "id" : "3854361d-3fe5-47fb-9417-a99592e3dc5c", @@ -2442,7 +3283,7 @@ "internationalizationEnabled" : false, "supportedLocales" : [ ], "authenticationFlows" : [ { - "id" : "fd44ea2b-052b-470a-9afd-216390c40d54", + "id" : "01b4b17c-bb82-41c3-b5b5-b9aadd21cb23", "alias" : "Account verification options", "description" : "Method with which to verity the existing account", "providerId" : "basic-flow", @@ -2464,7 +3305,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "88a96abb-a839-4405-97bf-fa53f5290482", + "id" : "57574e2d-3c3d-4286-9fd1-d7f4ab86c6c1", "alias" : "Authentication Options", "description" : "Authentication options.", "providerId" : "basic-flow", @@ -2493,7 +3334,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "cbe05604-280f-4304-bda5-ed5245537f4d", + "id" : "1eb0e67c-2856-475e-8563-5eca431fd9d0", "alias" : "Browser - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -2515,7 +3356,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "5275913f-e597-4a89-b416-4f9412b9082b", + "id" : "ff023867-aad5-4d19-a7da-60904727cd77", "alias" : "Direct Grant - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -2537,7 +3378,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "a0afd432-ed89-41c6-be8d-f31834e80ba1", + "id" : "c4f2f1e4-a32c-4559-9fe3-f88cc6cb63da", "alias" : "First broker login - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -2559,7 +3400,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "fab45b23-3353-4482-b690-07f3ab177776", + "id" : "bfb28a5f-98d9-4ce0-ae8d-75a7ba1ad331", "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", @@ -2581,7 +3422,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "f5eb0757-f2cd-4d4b-9608-d1b9ae4fd941", + "id" : "8b2075bd-9ad7-44c3-9a06-bc60a13beb7a", "alias" : "Reset - Conditional OTP", "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", "providerId" : "basic-flow", @@ -2603,7 +3444,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "521586b9-ade0-4f8c-aff6-3d6c357aa6e4", + "id" : "1fdcbed7-e44b-4473-ab7b-25037309660b", "alias" : "User creation or linking", "description" : "Flow for the existing/non-existing user alternatives", "providerId" : "basic-flow", @@ -2626,7 +3467,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "b21bb98a-9241-4484-966b-6f8294ba2186", + "id" : "2f6e9208-b0e6-4941-9bd5-8f83ebc25b6c", "alias" : "Verify Existing Account by Re-authentication", "description" : "Reauthentication of existing account", "providerId" : "basic-flow", @@ -2648,7 +3489,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "7ec2a1f6-37e7-444e-9376-dee7d442ec2f", + "id" : "f059067e-d626-4be3-868f-4c8780318497", "alias" : "browser", "description" : "browser based authentication", "providerId" : "basic-flow", @@ -2684,7 +3525,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "1bc2b251-bf69-40b1-ace2-e3be5037b910", + "id" : "c35098b5-3785-4f52-90e3-39b8f3841f0c", "alias" : "clients", "description" : "Base authentication for clients", "providerId" : "client-flow", @@ -2720,7 +3561,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "12a854bd-4d8a-49eb-8be5-cfc9d25cba54", + "id" : "c78934b6-5386-49e7-89e8-9efe1088f5b2", "alias" : "direct grant", "description" : "OpenID Connect Resource Owner Grant", "providerId" : "basic-flow", @@ -2749,7 +3590,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "99ebf3a7-674e-4603-a0cf-8fe4c6dd4cfc", + "id" : "7a08791f-0c8b-4e11-a588-f5856b75337b", "alias" : "docker auth", "description" : "Used by Docker clients to authenticate against the IDP", "providerId" : "basic-flow", @@ -2764,7 +3605,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "a241b9b8-9c21-4a47-877a-5a6535678c90", + "id" : "11e93dce-9673-4c99-ae7a-0edaf1c9b7e4", "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", @@ -2787,7 +3628,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "c9df7ad1-9b59-46ec-a85e-714fd682569c", + "id" : "dbb50df7-ec6e-4a34-97f5-b484f1d8a76c", "alias" : "forms", "description" : "Username, password, otp and other auth forms.", "providerId" : "basic-flow", @@ -2809,7 +3650,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "14f21f85-2bcb-4ed6-aaab-1ee237da153f", + "id" : "d7a3dff9-249b-4811-9f36-b78119a4ce3f", "alias" : "http challenge", "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes", "providerId" : "basic-flow", @@ -2831,7 +3672,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "bc7e40c0-9172-496b-8db1-3ebc20065887", + "id" : "ed4891ad-657c-45ac-9388-6c50d191124d", "alias" : "registration", "description" : "registration flow", "providerId" : "basic-flow", @@ -2847,7 +3688,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "ef97f42b-7f32-442c-ab4a-8cb6c873cf1f", + "id" : "f7c308b0-58de-4ed2-bf69-394144698e5a", "alias" : "registration form", "description" : "registration form", "providerId" : "form-flow", @@ -2883,7 +3724,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "1ee2b484-3836-466f-9f5b-bbf47abc5ad7", + "id" : "3fb75774-a3a5-4e01-bc4a-4e564451601d", "alias" : "reset credentials", "description" : "Reset credentials for a user if they forgot their password or something", "providerId" : "basic-flow", @@ -2919,7 +3760,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "4918f32e-6780-4ddd-a1a2-c3ae9d8fa598", + "id" : "822d5c02-9ab3-4a9b-8fa4-1f020c5ffe08", "alias" : "saml ecp", "description" : "SAML ECP Profile Authentication Flow", "providerId" : "basic-flow", @@ -2935,13 +3776,13 @@ } ] } ], "authenticatorConfig" : [ { - "id" : "5479944f-6198-48df-8a18-4bc0caba5963", + "id" : "0e613377-2aaa-4fed-bb7d-4dea69d5c340", "alias" : "create unique user config", "config" : { "require.password.update.after.registration" : "false" } }, { - "id" : "fd9f571f-0d6e-4ece-a3e5-fffccc1e4fad", + "id" : "ac6b9188-f0ec-48ec-852a-8e3b331b33a6", "alias" : "review profile config", "config" : { "update.profile.on.first.login" : "missing" @@ -3036,4 +3877,4 @@ "clientPolicies" : { "policies" : [ ] } -} \ No newline at end of file +} diff --git a/keycloak/test_user_lists/sartography b/keycloak/test_user_lists/sartography new file mode 100644 index 000000000..1e280bae9 --- /dev/null +++ b/keycloak/test_user_lists/sartography @@ -0,0 +1,15 @@ +email,spiffworkflow-employeeid +admin@spiffworkflow.org +alex@sartography.com,111 +dan@sartography.com,115 +daniel@sartography.com +elizabeth@sartography.com +j@sartography.com +jason@sartography.com +jon@sartography.com +kb@sartography.com +kevin@sartography.com +madhurya@sartography.com,160 +madhurya@ymail.com,161 +mike@sartography.com +natalia@sartography.com diff --git a/keycloak/test_user_lists/status b/keycloak/test_user_lists/status index e9c518374..d370b96a7 100644 --- a/keycloak/test_user_lists/status +++ b/keycloak/test_user_lists/status @@ -1,9 +1,53 @@ -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 - +email,spiffworkflow-employeeid +# admin@spiffworkflow.org +amir@status.im +app.program.lead@status.im,121 +core1.contributor@status.im,155 +core2.contributor@status.im,156 +core3.contributor@status.im,157 +core4.contributor@status.im,158 +core5.contributor@status.im,159 +core@status.im,113 +dao.project.lead@status.im +desktop.program.lead@status.im +desktop.project.lead@status.im +fin@status.im,118 +finance.lead@status.im,128 +finance_user1@status.im +harmeet@status.im,109 +infra.project-lead@status.im,130 +infra.sme@status.im,119 +infra1.sme@status.im,131 +infra2.sme@status.im,132 +infra3.sme@status.im,167 +jakub@status.im +jarrad@status.im +lead@status.im,114 +legal.project-lead@status.im,133 +legal.sme@status.im,125 +legal1.sme@status.im,134 +legal2.sme@status.im,165 +legal3.sme@status.im,166 +manuchehr@status.im,110 +peopleops.partner.sme@status.im,148 +peopleops.partner1.sme@status.im,149 +peopleops.partner2.sme@status.im,173 +peopleops.partner3.sme@status.im,174 +peopleops.partner@status.im,150 +peopleops.project-lead@status.im,147 +peopleops.talent.sme@status.im,143 +peopleops.talent1.sme@status.im,142 +peopleops.talent@status.im,141 +ppg.ba.project-lead@status.im,137 +ppg.ba.sme@status.im,138 +ppg.ba1.sme@status.im,170 +ppg.ba2.sme@status.im,171 +ppg.ba3.sme@status.im,172 +ppg.ba@status.im,127 +sasha@status.im,112 +security.project-lead@status.im,151 +security.sme@status.im,123 +security1.sme@status.im,135 +security2.sme@status.im,168 +security3.sme@status.im,169 +services.lead@status.im,122 diff --git a/migrations/versions/907bcf0c3d75_.py b/migrations/versions/2ec4222f0012_.py similarity index 98% rename from migrations/versions/907bcf0c3d75_.py rename to migrations/versions/2ec4222f0012_.py index 552afe485..0cd0195ab 100644 --- a/migrations/versions/907bcf0c3d75_.py +++ b/migrations/versions/2ec4222f0012_.py @@ -1,8 +1,8 @@ """empty message -Revision ID: 907bcf0c3d75 +Revision ID: 2ec4222f0012 Revises: -Create Date: 2022-12-28 13:52:13.030028 +Create Date: 2023-01-24 10:31:26.693063 """ from alembic import op @@ -10,7 +10,7 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = '907bcf0c3d75' +revision = '2ec4222f0012' down_revision = None branch_labels = None depends_on = None @@ -129,6 +129,8 @@ def upgrade(): sa.Column('bpmn_version_control_type', sa.String(length=50), nullable=True), sa.Column('bpmn_version_control_identifier', sa.String(length=255), nullable=True), sa.Column('spiff_step', sa.Integer(), nullable=True), + sa.Column('locked_by', sa.String(length=80), nullable=True), + sa.Column('locked_at_in_seconds', sa.Integer(), nullable=True), sa.ForeignKeyConstraint(['process_initiator_id'], ['user.id'], ), sa.PrimaryKeyConstraint('id') ) @@ -204,8 +206,7 @@ def upgrade(): sa.ForeignKeyConstraint(['completed_by_user_id'], ['user.id'], ), sa.ForeignKeyConstraint(['lane_assignment_id'], ['group.id'], ), sa.ForeignKeyConstraint(['process_instance_id'], ['process_instance.id'], ), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('task_id', 'process_instance_id', name='human_task_unique') + sa.PrimaryKeyConstraint('id') ) op.create_index(op.f('ix_human_task_completed'), 'human_task', ['completed'], unique=False) op.create_table('message_correlation', @@ -269,7 +270,8 @@ def upgrade(): sa.Column('task_json', sa.JSON(), nullable=False), sa.Column('timestamp', sa.DECIMAL(precision=17, scale=6), nullable=False), sa.ForeignKeyConstraint(['process_instance_id'], ['process_instance.id'], ), - sa.PrimaryKeyConstraint('id') + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('process_instance_id', 'spiff_step', name='process_instance_id_spiff_step') ) op.create_table('human_task_user', sa.Column('id', sa.Integer(), nullable=False), diff --git a/migrations/versions/63fc8d693b9f_.py b/migrations/versions/63fc8d693b9f_.py new file mode 100644 index 000000000..e723474c7 --- /dev/null +++ b/migrations/versions/63fc8d693b9f_.py @@ -0,0 +1,34 @@ +"""empty message + +Revision ID: 63fc8d693b9f +Revises: e05ca5cdc312 +Create Date: 2023-02-09 11:54:34.935801 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import mysql + +# revision identifiers, used by Alembic. +revision = '63fc8d693b9f' +down_revision = 'e05ca5cdc312' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('spiff_step_details', sa.Column('start_in_seconds', sa.DECIMAL(precision=17, scale=6), nullable=False)) + op.add_column('spiff_step_details', sa.Column('end_in_seconds', sa.DECIMAL(precision=17, scale=6), nullable=True)) + op.drop_column('spiff_step_details', 'engine_step_end_in_seconds') + op.drop_column('spiff_step_details', 'engine_step_start_in_seconds') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('spiff_step_details', sa.Column('engine_step_start_in_seconds', mysql.DECIMAL(precision=17, scale=6), nullable=True)) + op.add_column('spiff_step_details', sa.Column('engine_step_end_in_seconds', mysql.DECIMAL(precision=17, scale=6), nullable=True)) + op.drop_column('spiff_step_details', 'end_in_seconds') + op.drop_column('spiff_step_details', 'start_in_seconds') + # ### end Alembic commands ### diff --git a/migrations/versions/ca9b79dde5cc_.py b/migrations/versions/ca9b79dde5cc_.py new file mode 100644 index 000000000..8a7134f41 --- /dev/null +++ b/migrations/versions/ca9b79dde5cc_.py @@ -0,0 +1,32 @@ +"""empty message + +Revision ID: ca9b79dde5cc +Revises: 2ec4222f0012 +Create Date: 2023-02-03 21:06:56.396816 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'ca9b79dde5cc' +down_revision = '2ec4222f0012' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('user', sa.Column('tenant_specific_field_1', sa.String(length=255), nullable=True)) + op.add_column('user', sa.Column('tenant_specific_field_2', sa.String(length=255), nullable=True)) + op.add_column('user', sa.Column('tenant_specific_field_3', sa.String(length=255), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('user', 'tenant_specific_field_3') + op.drop_column('user', 'tenant_specific_field_2') + op.drop_column('user', 'tenant_specific_field_1') + # ### end Alembic commands ### diff --git a/migrations/versions/e05ca5cdc312_.py b/migrations/versions/e05ca5cdc312_.py new file mode 100644 index 000000000..ab6d1b643 --- /dev/null +++ b/migrations/versions/e05ca5cdc312_.py @@ -0,0 +1,38 @@ +"""empty message + +Revision ID: e05ca5cdc312 +Revises: ca9b79dde5cc +Create Date: 2023-02-08 12:21:41.722774 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import mysql + +# revision identifiers, used by Alembic. +revision = 'e05ca5cdc312' +down_revision = 'ca9b79dde5cc' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('spiff_step_details', sa.Column('task_state', sa.String(length=50), nullable=False)) + op.add_column('spiff_step_details', sa.Column('task_id', sa.String(length=50), nullable=False)) + op.add_column('spiff_step_details', sa.Column('bpmn_task_identifier', sa.String(length=255), nullable=False)) + op.add_column('spiff_step_details', sa.Column('engine_step_start_in_seconds', sa.DECIMAL(precision=17, scale=6), nullable=True)) + op.add_column('spiff_step_details', sa.Column('engine_step_end_in_seconds', sa.DECIMAL(precision=17, scale=6), nullable=True)) + op.drop_column('spiff_step_details', 'timestamp') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('spiff_step_details', sa.Column('timestamp', mysql.DECIMAL(precision=17, scale=6), nullable=False)) + op.drop_column('spiff_step_details', 'engine_step_end_in_seconds') + op.drop_column('spiff_step_details', 'engine_step_start_in_seconds') + op.drop_column('spiff_step_details', 'bpmn_task_identifier') + op.drop_column('spiff_step_details', 'task_id') + op.drop_column('spiff_step_details', 'task_state') + # ### end Alembic commands ### diff --git a/noxfile.py b/noxfile.py index c3f6dab11..e47f70052 100644 --- a/noxfile.py +++ b/noxfile.py @@ -42,7 +42,7 @@ def setup_database(session: Session) -> None: flask_env_key = "FLASK_SESSION_SECRET_KEY" session.env[flask_env_key] = "super_secret_key" session.env["FLASK_APP"] = "src/spiffworkflow_backend" - session.env["SPIFFWORKFLOW_BACKEND_ENV"] = "testing" + session.env["SPIFFWORKFLOW_BACKEND_ENV"] = "unit_testing" session.run("flask", "db", "upgrade") diff --git a/poetry.lock b/poetry.lock index b32b4247e..a1df93676 100644 --- a/poetry.lock +++ b/poetry.lock @@ -72,7 +72,7 @@ zookeeper = ["kazoo"] [[package]] name = "astroid" -version = "2.12.12" +version = "2.13.3" description = "An abstract syntax tree for Python with inference support." category = "main" optional = false @@ -80,7 +80,7 @@ python-versions = ">=3.7.2" [package.dependencies] lazy-object-proxy = ">=1.4.0" -typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""} +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} wrapt = [ {version = ">=1.11,<2", markers = "python_version < \"3.11\""}, {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}, @@ -113,7 +113,7 @@ pytz = ">=2015.7" [[package]] name = "bandit" -version = "1.7.2" +version = "1.7.4" description = "Security oriented static analyser for python code." category = "dev" optional = false @@ -430,6 +430,17 @@ calendars = ["convertdate", "convertdate", "hijri-converter"] fasttext = ["fasttext"] langdetect = ["langdetect"] +[[package]] +name = "dill" +version = "0.3.6" +description = "serialize all of python" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +graph = ["objgraph (>=1.7.2)"] + [[package]] name = "distlib" version = "0.3.6" @@ -487,30 +498,28 @@ testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pyt [[package]] name = "flake8" -version = "4.0.1" +version = "6.0.0" description = "the modular source code checker: pep8 pyflakes and co" category = "dev" optional = false +python-versions = ">=3.8.1" + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.10.0,<2.11.0" +pyflakes = ">=3.0.0,<3.1.0" + +[[package]] +name = "flake8-bandit" +version = "4.1.1" +description = "Automated security testing with bandit and flake8." +category = "dev" +optional = false python-versions = ">=3.6" [package.dependencies] -mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.8.0,<2.9.0" -pyflakes = ">=2.4.0,<2.5.0" - -[[package]] -name = "flake8-bandit" -version = "2.1.2" -description = "Automated security testing with bandit and flake8." -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -bandit = "*" -flake8 = "*" -flake8-polyfill = "*" -pycodestyle = "*" +bandit = ">=1.7.3" +flake8 = ">=5.0.0" [[package]] name = "flake8-bugbear" @@ -539,17 +548,6 @@ python-versions = "*" flake8 = ">=3" pydocstyle = ">=2.1" -[[package]] -name = "flake8-polyfill" -version = "1.0.2" -description = "Polyfill package for Flake8 plugins" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -flake8 = "*" - [[package]] name = "flake8-rst-docstrings" version = "0.2.7" @@ -867,6 +865,20 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "isort" +version = "5.11.4" +description = "A Python utility / library to sort Python imports." +category = "main" +optional = false +python-versions = ">=3.7.0" + +[package.extras] +colors = ["colorama (>=0.4.3,<0.5.0)"] +pipfile-deprecated-finder = ["pipreqs", "requirementslib"] +plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] + [[package]] name = "itsdangerous" version = "2.1.2" @@ -1040,11 +1052,11 @@ tests = ["pytest", "pytest-lazy-fixture (>=0.6.2)"] [[package]] name = "mccabe" -version = "0.6.1" +version = "0.7.0" description = "McCabe checker, plugin for flake8" -category = "dev" +category = "main" optional = false -python-versions = "*" +python-versions = ">=3.6" [[package]] name = "mypy" @@ -1149,7 +1161,7 @@ flake8 = ">=3.9.1" name = "platformdirs" version = "2.5.2" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" +category = "main" optional = false python-versions = ">=3.7" @@ -1226,11 +1238,11 @@ python-versions = ">=3.6" [[package]] name = "pycodestyle" -version = "2.8.0" +version = "2.10.0" description = "Python style guide checker" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6" [[package]] name = "pydocstyle" @@ -1248,11 +1260,11 @@ toml = ["toml"] [[package]] name = "pyflakes" -version = "2.4.0" +version = "3.0.1" description = "passive checker of Python programs" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" [[package]] name = "Pygments" @@ -1279,6 +1291,32 @@ dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pyte docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] +[[package]] +name = "pylint" +version = "2.15.10" +description = "python code static checker" +category = "main" +optional = false +python-versions = ">=3.7.2" + +[package.dependencies] +astroid = ">=2.12.13,<=2.14.0-dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = [ + {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, +] +isort = ">=4.2.5,<6" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +tomlkit = ">=0.10.1" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} + +[package.extras] +spelling = ["pyenchant (>=3.2,<4.0)"] +testutils = ["gitpython (>3)"] + [[package]] name = "pyparsing" version = "3.0.9" @@ -1786,8 +1824,8 @@ lxml = "*" [package.source] type = "git" url = "https://github.com/sartography/SpiffWorkflow" -reference = "be26100bcbef8026e26312c665dae42faf476485" -resolved_reference = "be26100bcbef8026e26312c665dae42faf476485" +reference = "main" +resolved_reference = "b439f69f23b547df4de1e8e0c636997f2fd4e33b" [[package]] name = "SQLAlchemy" @@ -1886,6 +1924,14 @@ category = "main" optional = false python-versions = ">=3.7" +[[package]] +name = "tomlkit" +version = "0.11.6" +description = "Style preserving TOML library" +category = "main" +optional = false +python-versions = ">=3.6" + [[package]] name = "tornado" version = "6.2" @@ -2158,7 +2204,7 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.12" -content-hash = "d804b8cbb34882f92cf19e5e59231aa7eac84764298fe7eae72bd03112e09496" +content-hash = "b16e8fb0cf991bcba08c3ef1ddf205f5899c622a10c79a7f50fb55a36d53b179" [metadata.files] alabaster = [ @@ -2182,8 +2228,8 @@ apscheduler = [ {file = "APScheduler-3.9.1.post1.tar.gz", hash = "sha256:b2bea0309569da53a7261bfa0ce19c67ddbfe151bda776a6a907579fdbd3eb2a"}, ] astroid = [ - {file = "astroid-2.12.12-py3-none-any.whl", hash = "sha256:72702205200b2a638358369d90c222d74ebc376787af8fb2f7f2a86f7b5cc85f"}, - {file = "astroid-2.12.12.tar.gz", hash = "sha256:1c00a14f5a3ed0339d38d2e2e5b74ea2591df5861c0936bb292b84ccf3a78d83"}, + {file = "astroid-2.13.3-py3-none-any.whl", hash = "sha256:14c1603c41cc61aae731cad1884a073c4645e26f126d13ac8346113c95577f3b"}, + {file = "astroid-2.13.3.tar.gz", hash = "sha256:6afc22718a48a689ca24a97981ad377ba7fb78c133f40335dfd16772f29bcfb1"}, ] attrs = [ {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, @@ -2194,8 +2240,8 @@ Babel = [ {file = "Babel-2.10.3.tar.gz", hash = "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51"}, ] bandit = [ - {file = "bandit-1.7.2-py3-none-any.whl", hash = "sha256:e20402cadfd126d85b68ed4c8862959663c8c372dbbb1fca8f8e2c9f55a067ec"}, - {file = "bandit-1.7.2.tar.gz", hash = "sha256:6d11adea0214a43813887bfe71a377b5a9955e4c826c8ffd341b494e3ab25260"}, + {file = "bandit-1.7.4-py3-none-any.whl", hash = "sha256:412d3f259dab4077d0e7f0c11f50f650cc7d10db905d98f6520a95a18049658a"}, + {file = "bandit-1.7.4.tar.gz", hash = "sha256:2d63a8c573417bae338962d4b9b06fbc6080f74ecd955a092849e1e65c717bd2"}, ] bcrypt = [ {file = "bcrypt-4.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b1023030aec778185a6c16cf70f359cbb6e0c289fd564a7cfa29e727a1c38f8f"}, @@ -2367,6 +2413,10 @@ dateparser = [ {file = "dateparser-1.1.2-py2.py3-none-any.whl", hash = "sha256:d31659dc806a7d88e2b510b2c74f68b525ae531f145c62a57a99bd616b7f90cf"}, {file = "dateparser-1.1.2.tar.gz", hash = "sha256:3821bf191f95b2658c4abd91571c09821ce7a2bc179bf6cefd8b4515c3ccf9ef"}, ] +dill = [ + {file = "dill-0.3.6-py3-none-any.whl", hash = "sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0"}, + {file = "dill-0.3.6.tar.gz", hash = "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373"}, +] distlib = [ {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, @@ -2388,11 +2438,12 @@ filelock = [ {file = "filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"}, ] flake8 = [ - {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, - {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, + {file = "flake8-6.0.0-py2.py3-none-any.whl", hash = "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7"}, + {file = "flake8-6.0.0.tar.gz", hash = "sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"}, ] flake8-bandit = [ - {file = "flake8_bandit-2.1.2.tar.gz", hash = "sha256:687fc8da2e4a239b206af2e54a90093572a60d0954f3054e23690739b0b0de3b"}, + {file = "flake8_bandit-4.1.1-py3-none-any.whl", hash = "sha256:4c8a53eb48f23d4ef1e59293657181a3c989d0077c9952717e98a0eace43e06d"}, + {file = "flake8_bandit-4.1.1.tar.gz", hash = "sha256:068e09287189cbfd7f986e92605adea2067630b75380c6b5733dab7d87f9a84e"}, ] flake8-bugbear = [ {file = "flake8-bugbear-22.10.25.tar.gz", hash = "sha256:89e51284eb929fbb7f23fbd428491e7427f7cdc8b45a77248daffe86a039d696"}, @@ -2402,10 +2453,6 @@ flake8-docstrings = [ {file = "flake8-docstrings-1.6.0.tar.gz", hash = "sha256:9fe7c6a306064af8e62a055c2f61e9eb1da55f84bb39caef2b84ce53708ac34b"}, {file = "flake8_docstrings-1.6.0-py2.py3-none-any.whl", hash = "sha256:99cac583d6c7e32dd28bbfbef120a7c0d1b6dde4adb5a9fd441c4227a6534bde"}, ] -flake8-polyfill = [ - {file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"}, - {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, -] flake8-rst-docstrings = [ {file = "flake8-rst-docstrings-0.2.7.tar.gz", hash = "sha256:2740067ab9237559dd45a3434d8c987792c7b259ca563621a3b95efe201f5382"}, {file = "flake8_rst_docstrings-0.2.7-py3-none-any.whl", hash = "sha256:5d56075dce360bcc9c6775bfe7cb431aa395de600ca7e8d40580a28d50b2a803"}, @@ -2499,6 +2546,7 @@ 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"}, @@ -2507,6 +2555,7 @@ 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"}, @@ -2515,6 +2564,7 @@ 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"}, @@ -2548,6 +2598,10 @@ iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] +isort = [ + {file = "isort-5.11.4-py3-none-any.whl", hash = "sha256:c033fd0edb91000a7f09527fe5c75321878f98322a77ddcc81adbd83724afb7b"}, + {file = "isort-5.11.4.tar.gz", hash = "sha256:6db30c5ded9815d813932c04c2f85a360bcdd35fed496f4d8f35495ef0a261b6"}, +] itsdangerous = [ {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, @@ -2737,8 +2791,8 @@ marshmallow-sqlalchemy = [ {file = "marshmallow_sqlalchemy-0.28.1-py2.py3-none-any.whl", hash = "sha256:dbb061c19375eca3a7d18358d2ca8bbaee825fc3000a3f114e2698282362b536"}, ] mccabe = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] mypy = [ {file = "mypy-0.982-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5085e6f442003fa915aeb0a46d4da58128da69325d8213b4b35cc7054090aed5"}, @@ -2812,10 +2866,7 @@ 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"}, @@ -2922,16 +2973,16 @@ psycopg2 = [ {file = "psycopg2-2.9.4.tar.gz", hash = "sha256:d529926254e093a1b669f692a3aa50069bc71faf5b0ecd91686a78f62767d52f"}, ] pycodestyle = [ - {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, - {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, + {file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"}, + {file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"}, ] pydocstyle = [ {file = "pydocstyle-6.1.1-py3-none-any.whl", hash = "sha256:6987826d6775056839940041beef5c08cc7e3d71d63149b48e36727f70144dc4"}, {file = "pydocstyle-6.1.1.tar.gz", hash = "sha256:1d41b7c459ba0ee6c345f2eb9ae827cab14a7533a88c5c6f7e94923f72df92dc"}, ] pyflakes = [ - {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, - {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, + {file = "pyflakes-3.0.1-py2.py3-none-any.whl", hash = "sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf"}, + {file = "pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"}, ] Pygments = [ {file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"}, @@ -2941,6 +2992,10 @@ pyjwt = [ {file = "PyJWT-2.6.0-py3-none-any.whl", hash = "sha256:d83c3d892a77bbb74d3e1a2cfa90afaadb60945205d1095d9221f04466f64c14"}, {file = "PyJWT-2.6.0.tar.gz", hash = "sha256:69285c7e31fc44f68a1feb309e948e0df53259d579295e6cfe2b1792329f05fd"}, ] +pylint = [ + {file = "pylint-2.15.10-py3-none-any.whl", hash = "sha256:9df0d07e8948a1c3ffa3b6e2d7e6e63d9fb457c5da5b961ed63106594780cc7e"}, + {file = "pylint-2.15.10.tar.gz", hash = "sha256:b3dc5ef7d33858f297ac0d06cc73862f01e4f2e74025ec3eff347ce0bc60baf5"}, +] pyparsing = [ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, @@ -3372,6 +3427,10 @@ tomli = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +tomlkit = [ + {file = "tomlkit-0.11.6-py3-none-any.whl", hash = "sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b"}, + {file = "tomlkit-0.11.6.tar.gz", hash = "sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73"}, +] tornado = [ {file = "tornado-6.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:20f638fd8cc85f3cbae3c732326e96addff0a15e22d80f049e00121651e82e72"}, {file = "tornado-6.2-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:87dcafae3e884462f90c90ecc200defe5e580a7fbbb4365eda7c7c1eb809ebc9"}, diff --git a/pyproject.toml b/pyproject.toml index cd1f7f359..cbf0b7ade 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,8 +27,7 @@ flask-marshmallow = "*" flask-migrate = "*" flask-restful = "*" werkzeug = "*" -# 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 = "be26100bcbef8026e26312c665dae42faf476485"} +SpiffWorkflow = {git = "https://github.com/sartography/SpiffWorkflow", rev = "main"} # SpiffWorkflow = {develop = true, path = "../SpiffWorkflow" } sentry-sdk = "^1.10" sphinx-autoapi = "^2.0" @@ -73,6 +72,7 @@ pytz = "^2022.6" dateparser = "^1.1.2" types-dateparser = "^1.1.4.1" flask-jwt-extended = "^4.4.4" +pylint = "^2.15.10" [tool.poetry.dev-dependencies] @@ -85,12 +85,12 @@ xdoctest = {extras = ["colors"], version = "^1.0.1"} sphinx = "^5.0.2" sphinx-autobuild = ">=2021.3.14" pre-commit = "^2.20.0" -flake8 = "^4.0.1" +flake8 = "*" black = ">=21.10b0" -flake8-bandit = "^2.1.2" +flake8-bandit = "*" # 1.7.3 broke us. https://github.com/PyCQA/bandit/issues/841 -bandit = "1.7.2" +bandit = "*" flake8-bugbear = "^22.10.25" flake8-docstrings = "^1.6.0" diff --git a/src/.coverage.jason-Gazelle.473795.719220 b/src/.coverage.jason-Gazelle.473795.719220 deleted file mode 100644 index 3c5fc7087c6bf5119e52f8ca861578c24a7e868e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77824 zcmeI532+=&na5vG_uMnxx)1AW*|KFt$4Ig*+p=uQS4<$AKrqCCjYq9fk2LmN>F$v& zJGRu5a4lQK7F$I~kzlHJ1G}&lwnAYxwUB5x1p$hfgkrM}MPe1HqF4e3Qbq|Rk@kCU zx<{kSD;DL6xL(_u@Adiq@AvMbXWsw5TVsYQM^jotG30Hi2yq-5kY$9B5B^Hw&)(eN z5bPbWT!DKfrw?`9`R<_fK@@O(21&<*$E5baBf*gWCxJ2V-}}GhKH-hS3AQl;i~u9R z2rvSKfcd_FyRy2P%bqiop}1;jN<`IipTUE79NvHQuzYm?fm;vDxnuHHpA1`jyS!i4 zQm5p!s>#tS-f)03M>oMw0jnd8>7Mi>#?pRa27@RnMu|8XIo$wcI!1b61v@ zavxJkm=rAn|NRR>0|(}Va!V8*6iI2rSpATuBqO7$-X<&g5Jpm<^R$r*t(HoJjFcRY zB}p)odd!HWlCpYQjbsdUc-a89VQBUS@Cri%&lBla3@CYqC(#1J4qkx8U+bO}ZF6YC$AUbX2I7V}K zWs+ek2ysWur00#d+czpHY0DTg3cs;BjP;?VF4D;Xn2_QMeQ;V$?H z++XZ*S2i?oAG?Pn6pSZ46f^X^!@D5SMe(?tijpjY@0N3s z1F5+%&xC9kiiR_qoU$$irR$p7uvpL_55-eM3)31&F}eyF1j+*YvS=n5!C6JeVTh#0 zR81LCJFK(0Vqv`#5+t22udDKK!%9gfp9I2Pd8f~;cDXBSYPhVIBqJ-fEaP5~gzT7H zrWmzPB~(SvXm&wzy+YEyW4@HM^N4i@g46DHRqn4@DLB@3;V#SJG2Mc@vb>x#b2$Q+ zOZd;ZAQ1S-d=^+#5v*Q*S}{iDrP}df5Z>%`RqiQYNjR1e?!uq0`|fZM$scnQ`UxoX z@gKiHGCndd`911*`hgqQ%eHnM3)04-lk>^sb|`0| zkyDsFFuMXAcsJ(*F4J-`IFzGcUu89Md@Vsx$w_Y@_|G;*fDvE>7y(9r5nu!u0Y-ok zU<4QeMt~8x@d)sogLC8lzaZ^EQd$a22f@KMMt~7u1Q-EEfDvE>7y(9r5nu!u0Y-ok z$Pow#e4S)3o9NuY^X1#{vVrc-?(X)k?)L6(xvQtQYiDow4#~mSR9chnJsmqbI?W&_ z)MX`my~Kx`L!+sL8akoqsbr`lqQJs{P~K~-ku)c*3s1!ipPfFc4IV^B)hN*P;F1cwXmj1$0t z7=d>JfdF5}*<%xehcD;w&;;-2YdC8h!r|xZy!HTu6N2QBW^lktq&ISocS0zcMn-@U zU<4QeMt~7u1Q-EEfDvE>7y(9r5m*I*;y$>jsKEiB4)GWGhEge+bKo7eF#?PLBftnS z0*nA7zz8q`i~u9R2rvTgPy&*Pge=b$F1Sx?sS|3%&_g3JV>B}q(iP1}jc7`GbUe4< zz8${YG^s4V_&%g-k%ec%*0TJNu4-d3`2Jt~+_1F+%kB39InfLV*%~S;5~*P|4$J7y(9r5nu!ufz=V< zIUWV^`~RHuCW8NLV+0rhMt~7u1Q-EEfDvE>7y(9r5nu!ufg6wj&j-DD{{M*QERudH z{Y?4^d<)>i(%(rRkxob-mfkPDOX`zaq&g`m{z`mVyeR&I_*wB&;yFN3{u%!_{EzrQ?LY6=`~&_T zf2+UF_onZf?|I)>e1GFT@BJ%pySK_KdS3DTyXT)g9|1XRV+0rhMt~7u1Q>xElYr-l zz)|2?q<$C;yw>~5hJ2Qu`{S_JvpkKKg4`N>qUVY}F&KhzSe@vjs288zI z_WL{s;F6L9$(gy*{ovZV|E15zkq9zg=g=VPsULuY`v%TWJorrXZ@VUo(No+sLY?^L zL4>LXL;Y}muz&Wghn;ZKf{iPJpM)+#92}fP4rI#UD3Y_@eNN7Mf62bt-^|TDFtP9U zSLZG?^?&YR0bh5(BTw>Z7r5MLikrfR5SqqvJYc5L>ku{p9t#KHKb)>b(>SeMwIOHsnUKjOr1-U;v+(E}G(mH*^;p_z5!WVbLv8L{;m+lY3EeOR? zXHgd%+SoO7_oGi9o|5DIu5Eie;mEz6v#oQF4e~sK|5AUI6hJcY?1RLP!E~bO|KL%l zYlXUdvp zG|BDW1kR#OpE+B+5gbh$XYTI#@3~JR<&}vB-rI;TYaDz0>4aCtPI*i}_tQWFI5#w0 zePnv}-@e8B>S3><{`qHqe-Bqt2kwr#CqDPq+{EnM#9z;S`#g&C$ZfXOLV&Z!YG>yl zx5XcV_1=RQt;t{%G`ll&n#;*keXW1kGg z3vy&#H4qH3rn_YW*rOX}&g~xVsVKhs^c5Vpm_DQf5+hR}rU>L9*;kDzRKN7#SDdb3 z6}W4wu0HdFsju~?BA!avEvY>I{EnguaBZwOKjH5=`{;#m1WE34I8s!8sn=Tuj z`lsB3el+=_yBI&SILbE^fn%WP;@sJ2bYkY>H?Gv6!O7yTI6t6p=wE}+x_j&pV^9JmK|&yUhQ@ z3y*UyA2>yyBj^QN>vg=V`+H5_(}ije>~8m5oqOZnV+dt=I}$ud_PX)S?&BkKoZkh` zD%S^Z1Fr6EPS_cB&b~F7r zI9xooyu;T69!!;n*+BB{#Li0A*0h{XuL`|q0cYw73G73s3{ob-L^ zDe0Ti*QH0LFG*jJ9+W;UeNwt#Iwy@uDQQ$vqz}R9z^&3@X`i%H>Vz?ZjZ%$NCIuyz zI48a?{!aWQj2HY={4ep6__R1BJ}y2centF8@nP{ZFn;iH(G<_X7(!fB#pB|g;(Ntg z!~^0UaXXACY!Ms8Dv-lAMt~7u1Q-EEfDvE>7y(9r5nu!ufw!9g?tgMeju3P6&BPo& zOw6G}#2h?G%z*>M?B7q!zyLA*{lx6sN6g;6#PszMvu6)6y}iWj-c8J|UBv9%NlZ@< zF*|k;vwb@;+qMzY-Azna7crfk#Dqe`baW8Y-cC$g8!@e|#N2cfF)b~`Y~4ysb2Bkp zwh*&!5}e#05N_tRKWRsWY6m*#^WKz?Iy7y(9r5nu!u0Y-okU<7Vp0(kzP z_5W|+2xdWJ1Q-EEfDvE>7y(9r5nu!u0Y-okU<7~we*d5K|5;LC1Q-EEfDvE>7y(9r z5nu!u0Y-okU<7V#0(kzvQg{!Nz9@BxUl;3xpAR+!9u746|JmQ^d(7A2{h~MMx!3)g zJL9_I`hfF?&O3x>h4=8^;=3GQb+mIAxCZo4@b*>nWp3>Bs%WEv&l>!QAN$jiwT6=!BxDk|C(IPN)$>4~@i((acatS2QCvqABUo z@mvzRZp#`6%TRUPLc;z3T5d1$_}!m?Zw(lC{=qpWT$9EnPW(i0E|>`XE->tW)_=hF zFTx4_Rqi=o7q5CB;r4nP9Y-CPJr8hy@IVVvw=2Qf;<7{vu>B-hHFPap%-8WIKR z0}^IGy-uO!vEA*$by{Ki+()ljVT}>!xIrF{r$$B~VE~Jr^fGB)ff@;GYE;$KWCXYC zN~tw1Yz1mWQ;l5H3jE)0283)4l?-YNh-k625mpT7nh)WUD-6}3p`OOI;3n!x0^&kb z_0h1AI;rBORu6RrcJ?56K*2`SCuA#W#)z%J9ut5BnoemrJ~q%REb_%S?(l^5aotc8 z1rEE2MtsAL|i&LeGeGK3VK9~TdwQesA~A<|B-oV}hRNF;u0&C&uP;BSz& zzj!PY{4Ft^LN-VR$@B^_im;r0IwD2b#;q(kB};%&i8!P^4g4}8G? zWB)PVCEo|UFM0<(Kl9w}e#sqmz3jTf`JD4s;iAySf05tdxQ}}kdjB(U`zkln*&v{- zw00vIx)#ZecbrOTC!_JysW9#!tI6Sz70t^JWSd+)=x|fiv2-ANtWH4YJrpHaBf6$o z3t?}h;c>n-v81JE9U#MbW?2mgYNsLSPZ?!2y&FJQB@J0tT3tdZ-ySykYS7}Rsb!gY zUDI6!DoWQ!#eDq*#g&@$$jtWqkRgc} z$BkG93aFGXE0^(w)4C=q1wl@VNc8lg(U!3i%4NOP$~adH{!Y*c`Lgp@rlW{*hFDyL zLVCPc0tV-3FtC#2d{qy=pB2IPvlM;Dqww}}ps^t3WM|FMp9+A#I>kWSv*f1R4+)ND z4Yh0!3*!BZ4-kw~L{QMrobUn!DpkM=)8@Jd0)LW5;0r=+a&8Fr8n)^245>9Czod6z z7kBDuC6R`4L%ehVV*R`eB&=blZZ#6{HF^J?^!+C*Ca?$y|2Y97ehurJ)r7ww31oQi zKDBn~?t0!AcpG+rw+GkS+X4^n;=qHQYv)11{6Fsh*P(}yG$Otr9t(aycrftYK%f7c z{sCD1U+ev>x7>4|dk$9r|Bq|b`J(ffa9MaS|3m&Z$B!Jha!+!taO>N)nSnk?&UI@S z?v>lqEB92bGmyB=;yoaznTDJd#xa+Ut(v}G&{VySnhKJs$?pa+RC=lT__8Kd3ubK2 z?1IcfrRH6_I%r}i0H9LyT5Zk6Gs_b_lm#rF$26TgKmnBzzI+-W-L2g8U2d5Su8FsU zj5Vx@S1vm2m{>T!Z92Ar04iev^BiQ8wQ92ZeAS;z}Yj)?QOmu+~nmNPn z3Ff;7-cC?JWjHU-!qz~NNI?;0xos#WZ41SQWg%1%h%fC)x@D6Yl@}ef3D15PvV83;s4330w)><$ub* z1N#57y(A$FOq;+d<2@URHi)g10ny{8;&Nr88lHDoUyvx zWN4=F4KmYzm{#8+k0sab3}^7m@np(Z%OsQJ^$@f45U8OtOp{l$q_2}(s#rM2$sYt& zbSH!C{!PIU7Iy$t&>i1g{4T2L+YcJ3%+clJhrBAk+`FizZ-Ba(72ic2>xV%bDodaX zaxxwpaPI>MRL0*ekL~=j_+8YAy�jFiAdXz&8dIWK;b9e~IhMNV->?abFTu_padc z!FRj99Qbyi*Z-J51n&Uc>Ambd=J~Pb=wD zy$%ct7vehC_>0R{gP>qmTo@C~)EdrAU(fpjZ}~yNJhf^0kwN3cA~U^uFjdA3savSO>@($F=KFPcB`kynC(dsa52l#Y?}7q>K_sBJKCy zbdN@tS1igCalN)R-|O@J-|yW=&%FPAw?@;d97$?%B`tTO0OB|_Aj=3L5B!zDpS3x` zAy_+LxdQiUP7i9o^WA>wgUILj43bXxk4tU7NBlwWPkdwUzxRI0dD0z&6KrDy7y(9r z5nu!e0poo>XGK*NmpzwOhGJ@3Q^Km2`}7~WK;swPLGF;$KxhNEF69ZihL=~30XI-{$@xWy5%dz$Z?^f)U@ zO1O`yBut7HhX3A0p@9PnLAfOY4+VXS^gQxf4(Rd1D*d~CiG}JnoP**X*HZltHUb>uoXkIHh@d2Q?g(C;<$a$Pju6E~Y_okC(VAmWsE5zkOco#*dg&fCd z?ygKCdQV2pM}DikaAzwCMk3iN<3K?z?8q)PR)eoqVI~#Xpo0u$)Uw*jieY|g$x2^fpu9VlL+IiqT?`x zlVhr;jHvDA*<7)((FqBXPN&;Zaio5=q?1nqq0YS1V^leu71h;T)=iR;8C#}tE=odH zOs-IjTBqWwqGvR#Ah}*4Y2C32MiN!C6sO#u>RB zfy*WQXI~Tud}JXDEU5_AEO|X^5`)qtr9?HzvQP%+Y5*BuIIO_M%1|J(hMAA`JRWh-#R<4R)Ktfp}7n|mr0`8ZEve{y99+$c9eUeqCHE_tT) zQ1dJkNqIcG&n3uk1^JeVt9LORstamA8t?%EcmjU^`+lF98* z&O#%nFnM5h1vv0-&Ieqk-$yzqiv5Du)y797su8yv*w$84$t}eN=r?+!g@6K+?##dLElkPq3JKH-9 zKPS{?C2PIJhns?<$+#Lksp!c>usy86!hm3EB9(+Sj}yVMsFuzsF*Px!2lZ4m5*bfw zry{ZBc-xQ?KBXpx+dkBF`mXn%zEf{YO?0<+b_Qe7A-Fv~noN*gSOuuIrQljv)1>1Q zs-6ypLUARU2!&v^MAO}Pk-s4Q2uVMZu1UX;uCOR(1Q-EEfDvE>7y(9r5nu!u0Y-ok zU<4R}cLD()U&~oz6M~B`1|ea*lUGD49k^ zfDvE>7y(9r5nu!u0Y-okU<4QeMt~7m1A(GGxF}F>gHN0I3w%R~l*l>o4%-+3Mt~7u z1Q-EEfDvE>7y(9r5nu!ufp;hY$v{Gu=L#3xr?lirHJsLiBhmC|W++Si@gKy`ik}kCiMlu}9v9oh zt^P6p3I84b!~Q+~c7L_M*zffH+V@f4dEb~X;XCHL#kbv8>nrundcWa)#QSOQd9UUj z@b-9HytSS;J=Z+Xd%oiN8~1tlU%A`dm2T1XitFE9|K$1z$YC2Jzz8q`i~u9R2;7(i zTt@}YU3|2s^3@3 zv_H4s=Q;?N6dz2?&X*hj*Y*Q1eLjXnknuW)22oGl036&uaDMW^XCi;wIaP$7;${%) zz&8&fR5=*zhx3E|b8kIthnp5{TmXI&I)FGhIE8G;kiijvgvKgC4c0Xe_U@g1;HSeKm1x>F1z&U33jg3N+~DYivtqBUeh>C>&-n`QBt77g;hY!rT3dP6 zw;L|lv^()29I^%6yI`+$SK{hC=js7xanIOHZ^uq>4edOC_UGN+e&p*j#h~e@c(`d0 zIiBj6;&{midxIpU40?9J9pyV_waJTIaW}ZPbzg)8-w$Ue;TFEA3yw8*UA=U_A8tV? zhB^YBaAbCb-9fRpWGylP( z4#zYXm;%7lJOYww&QufCQ4BuWfns1yosi6F9qWvi;`C??DLQ zG+cx~4%r;da7JvlIkscF-R5Y*w#lJxgKS{DdmChfxyeW*VSA_w5t1Ofa@x|3;Axk6 z0ww1yek$Ik5zfU^L>OduY;*Y^pTt`qRx!m@ZpFg3&c1U0559v2r^zY&;j45v!kN;> zSxs^}w}3OSuH#hz4i+pP4QoFerIm}!bb@_Q>%pf22cvs{}!it*X|m8 zcnZlViyZ|SvZF7@@3)vmF4`+|7vT$`0LpEFfhp|xIQMb#bM@G5o8k|{5tlrG8v0}? zUXU&8sD@yO)m_b-z#iK)dv4EgPkGVRr?23+#q=Q^kQkW;F#(W+WKR{QQ1#M-U$Hy< zmEf+ay!y-!roYyo47(~|x47cO^E(6O;M!b%e$v}>_R$NWFp`{Qa3oN6sn=Z!j?&T- zvoG^SCE#oZFUW z3FCG?xhIj_X5MrV#o)GU8-z(lC z9u)VAJ77d%n^-Saf*iIn0*nA7zz8q`i~u9R2rvSS03*N%yxjzF|C2j{=x#=cinwyE)zMYt+CSta2 zBWCMXVj3HX*|LS0&6|m7Xdp(GiK(wArml{d+FD|2YKW<>CT7znVydc$sjMWXqJo(6 za$?HLh$$^4rlf?J;$mWoiiimWh>;{>M3ET3pBSHy7%v$r;5;6(=XMk0auMTn660_X zW499{2*mI_F*ch3;{jy;ABJq$#t1M1i~u9R2rvSS03*N%FanGKBftnS0yi)LJpa%7 z|2J?1v!F2oi~u9R2rvSS03*N%FanGKBftnS0zd%2|IhmWEGaMoi~u9R2rvSS03*N% zFanGKBftnS0yj1RJpW%Iya!2Nlsd()i*^3b`|EuV`x?Ce?CtP8=4p3-(d~EL>wL|b zaa?hH!2Uz~9m2E1d-!khowl#q+PDi`J$lH0`x+S;4k0V8{ihG%J0-rl#wWAO7y(9L zV+k0%kae#;cc-F}$p7=_Rag08Q}{j80KMOMT_R#cOJ-7_pz~hAI7^p8G!c%blo)s} z8iJ7ZQuSTc;!$0XCKI8wqK&9&P*G*Lglx$MsZc=7NFuH#u#!rnRLHi_R1$|@+Eqr> zP+E(QjHsG26jMXi5Ac!{1F9;hCsIq5rJ#&@UbPfhKSB%`$_+`#Hf%)Xgp-=4#*{Qp zwGcTeRZCBRpi-kk$aZeDpcP2Te`3Sw&o5dn5e1|GP`zOjvQCZ68cd!2E~w``#t%Pn#jb#`=Uu9%Te`SNkv0r zpaV)q@W06@6S8eo1gNLOY6=&~3%^$nRd_T#5lSS}p-3{57!IkLmc&IsHMKMuP9`GJ zkzhfZ+?^JTQ&fl)cjcOSX0tMy7zvrDAwG{9oRGCs(F7_W5e0F*92$yc)RYz_jqaQ2 zwG#4J)VLCj6<|1Mc!g{g6$}d+aPbrxRT9Io#c^_A1H>qq^e8Ss!?{-OLIN3}){rPj zACNHn>2(TCkF9POuG0$B=YD$43UiD=#|`pOEIBd)2?JQ{qL)eY3e<2&QzNRTCc?N~ zS3<36VJT3=Q^}x~fUp)#r9(;@y5>W;XBmr@u zsrqOrojj%DrdAJi1y=STctF8s!y{xXXvT=8z#0>P1e!`}I6gMfD=hNGH}3F+^a(w! z#tSNv;09D?;f$V6#zQGZ193p3onFl3Y2f-JsYTB$tvLAIKzf}TP%y(X!tMj4Jr69tHt>;s{_^qN1bXet2I zOReu{YANu0yAcqwTc~6nv(6)Jb25Y!S{N4(jVsY~t|8J!ubjP}B1j}&YR%FDA>gl{ zw!e5R6Z|bU>_XO0GcDvAp-{c0Lc?krx=T99XvFLP>rnzpk4T5bXT;n5m;AT+zVG{h z_s8Djo=ct&xLR3LIJyt6q;~t6<%n@Bf ztbwpM(C|3lnpoD-GY^pAJfpN41hvr+^rwt68tzRXtAd6sGp#P8ly46kd=+T%($uoT zysqJ_1QjJ4qhg`{f?~@ksQ@J{6qQ)z$o1xR4O=;=TE}tPHJ5Hy4+_vsmVpL-1IUm> zjN?Wu1qD>fm(|Po!f9Otm4F~SMI?G^$!N=1G3Bz}Y-OA)0)HoIgnY&ME5jC`oFSGL zp^zT$m4LxH8VtIoX+W^y5D8SEm?gYnI$_dLhBl ztf5xyVL`l~@c@DeiU ztl~~Rt;AC>Zitr-K&+p4fP{7I)U8DVz9#R#oxcBM#RL`s;Xfxp#IIw0vzG7|B!LVM z-Y3^D-CfW70&hb$@b=Jpdt2baT^x9@YyCVZnE%K9|624Al19WA#N+<&`w#iP>+AD= z(>nmG|7+Zzb(gvBbI!x+|Nn7}+F!IE7cL9$<$uWEX8V!tR_;lz1#W%YHpABk$+>p@ z!o7NXdi9>Fc?J@!8P#? zkg<+6@#;l~6%&i+w+&l22%s_+u)rZFp`gTab%BU78l^*l2(nTsw`O-i%48=fp_wzR zo?yOf;O+ngREG2NEG!Kqi4+u3hBF9SsB}~ET2`LkHn?_BvW|`B)$>VS$!$v%#};eto40 zcf;EZs;X%um(^4iw0X{Kr`6h6KA(KP2|!S(#0N1r1*RBod37}uu(*Sug6{a{(sxk}&jHXtWsWW%Kjc;UmEJ`)JOk9ltoknMSU(KfP+0<9 zkdyJ)fO9`Upfdh$dTiyFrSGCn?gJrIhDq{C1HLh!Ae-X%|BD@8M$*0Ftn-qnI(Pe@ z_rKfmW#6}bz23*XL3jt?PWNT^ao3Ms$NnO#C?<*#U<4QeM&Je~K<_=J-K|L@}Bjsr`C{zmM-yX`CtDa17iRH diff --git a/src/.coverage.jason-Gazelle.476451.578823 b/src/.coverage.jason-Gazelle.476451.578823 deleted file mode 100644 index ef7f5c499e4d86a1876c0ad2756b2056f2b7908f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77824 zcmeI532+=&na5vG_uMnxqg%4BmMvRWbc{x}Wm}dl`HBf-69|Slu<@uh>XF8tE8R1) zWyh9!60T*d*kY>)DH2T8ZeSO-!d58ErWO+IrXWBOlTd8dp-8MERTN9WK*}hAB+`EG zP4{SYdBvhU5!Y*5^SwUb|NY*5^vwI;cWW%8%F&dTP%`p16hIt@24oo_~9zcfQ*%eGvH^pFz@b|1qh<_lQ5}{fTeP{rBE4IZwFbaDr`&03*N% zFanGKAz-}E=d7x!;d19P%1~U*Xi7xY@}K^LcO2e-^ssz%|AAW%%lTvSR*wu@M~A#$ z)>5bBw5rL`SX`B3$>CT;$;6T)a%NPuuFmS}Fs||77}Rd{AzQ!h<3yZ5XQ`(v)OmRMp#Mr4YhM3Ur>%nQDm`OdBiKUXVdRmQSGwSfN0c^+6tPS85hX$TChyyg3zti-qh|c`Y%iL*RZr&UP zamkd0b^b=|HQY=zC$otmKz<^dNaM(XJMtc9QY+oL(!H6K8Q4|F%`$O0AKnGgX(7ik zn!hWXjNOw}3z6S0&)?Zjf{{$M%Qz5_0ycXcRlCbL1gTOzt=|)ehF4h0W>RE743QrW z!H4hu5|^{8v61`OJtU!EJmH~OMlU$r3ldG?@Cr!>pIFeukIShj$ujtE zIUhNYnv3&H(1M|8IHSoa^FmO%uBi=+1r730JTc)H;<=6+Nq21|9i``MRr(z}HSVB02KOOhoVIz`1<|OnJ zQ0U`7et~3sWM1-n)bWlnB@U%YT8U|pWuXkt*8noUa9Dwhm7!ENL((taCCL-lJ@b0= z518M#*uzz=I?Z_>oijE5(y+s~MrQ)iR%vT9;;Vn9N71L$n_0r0yfBqTz zIDW>+SPPM2)hW1iKMHxx%2wb=B$VW^Sxw>EH~&;9@^PNT{^ZLJxKVC_yr@IYT=Y!q zq2^g!P+8CKOalu1)Pype&*eBSik^6CR9*78d?j>9$*7rFLY46)L<~t!rxaa|Xeyk9 zDzvqQzh3O)ND7DWC+;P?a6`su1Q zs-6jk!wDsp42NO0M9bZHk-s4Q2uVMZu1UX;uCOR(1Q-EEfDvE>7y(9r5nu!u0Y-ok zU<4R}cLD()U(Z=%6M~Dc;PB7{@8xSba~#6v7y(9r5nu!u0Y-okU<4QeMt~7m1%Z-2xG2zQgHN0I3w%SFl*~Ku4%-+3Mt~7u z1Q-EEfDvE>7y(9r5nu!ufp;hY$v{Gm=ZY8Hr?u1xHImVTBeBeAb||PTS|&B3De2Mi z{DS)q_;S;vvi#!vpsqz0o(Y@F@`Jjnjm6;mfAMp}<_;{k-wWhK!zbiwsi;V#hSfMM z``1z+MGwc4dIr8lSPfg>CJBm~*!TavLsK)8%?L08i~u9R2rvSS03*N%FanGKBfto( zjsVZ`$dBLu=cG3g{AU{@zz8q`i~u9R2rvSS03*N%FanGKBftpUfCPBn@5b~0M_gx- z^h@by(of)903VkAPWp&+Li(`ue(7COpVTVVOMdZJ;>+Si@gKy`ik}kCiMlu}9uqsn z&Hgd}asM6uL;l_VPJgYx)bI5D+V@f4dEb~X={xGX#kbX0?<@Dtc)#I&#QSOQd9UUj z@b-Ayy!DbV>vD`)97^wn*fi61MnYC*P&?~Tr|a> zM$$AUkl)8g@Nv9N%}MYFLB={JrD^_k?8LsLCjlFBB3VWa2wyOOPfQ1HFGkJB6bM=6;v}bI(w`&KuhIX7k`}1wye&p*j#h|IDc(`d0 zIiBj8w26yc={9h0*>({Ud_SC>fLr*IZaCK5ef84)ez*mp zIO+<7;Lyg<%-xSZd3Z{W^Sid~?SdoscFnfUJvPYm2>wg`)shd%z_Sk$I|kE*rvHOS zU5+U(FbROCcmyQzcA2XS!tK4m*{gT`9PyFK(A3~ypsU(3=&N=h-;}cx&IUR!IouuK zDDQZ}*LY`RJ2(g0ufCQ4FuWftu1yo&q6F9qXvi;`C??DLQ zG+cx~4%!^8a7JvkIksZE)#hlyw#A`tfox#BdkbWP*@OduZ1edapTt`qRx!y{Z^ptl&%AQ~559v2r^qS%;j4Bx!&P*eQ?c=YHyI1m}jv ztB*|2{@b^BPXp{#Ha!2#@9*I%>%rYw|HS9snwyxNoA~RwZ=XkT9yyKnItXy?Sl#R# zWc-m=FTB=r;Sc?Rcr@yG>uH#hz4i+pP4ZuGerI;>!bb@_Q>%pf22dI`{uZZs*RDEz zcoNAdhaE*3va2u8@3)vmKH97E7vT$`0LpKHfl2K6IQMb#bM@G5o8%9{5tlrGn)+lY zUXU&4sD)sNwcV{7z#iQ&b8h!=Pi4u~r?23+#q=Q^kQkW)F#(W+WKRvIQ1jA*U$Hy< z)!?qHzWU4$roPsninyv^x3uc`^E(2S;M!Pue!|;x_R$OB2$Gx?a3oN1sn=Z&j`H&3 zGcWTcW#DWsn|Y9*z3}3k16|}?ZKZJNSm_gA8yTFv^4*Ds&%fON$2n5gV zdZ(O&UNrflvjji0B+54iz%dZGICnN0otU}!jVrZiaIz#6=LZxH{j2|3hbX}X4bsKe zgj2~EX3sl3BJ5X+Gtd0s*NzfDxSRbm54`Y=-`oj)pbuAjeE78Qd3*GgC){3emwTUh z;c?F40jKD(`Q2da+_rahf3Nv_x=`bS-R-Wcb8p;x451uvMS=^-ZYRFkd3`12Yhdt)yeXq3|q0d5in zn}f%ew>fOs+HB>V;C8oPeXTh#3_0Z~lB!%yc>e#0Sc2fY|E@{DmVPc>kuFQmN#B>A zlD;W@U3ygdlJo`XLFv=dC#CzPbJCcUl13#(`Vfo`+$tTG_DMUXE*K-&DAh{kl3#L& zbK>jb@5Eoic)?G_{}L~WPm5FH7y(9r5nu!u0Y-okc)JPU{wH_j2r)O`Ow8fK z#2h+A%)x`i95_JC{{6%Z3=q@bPt3l3#O&QmOkW={d-f31+e^&u-NfwLMa<5f#PswK zvttJ_+qV<5Z5uJ&-Nb}K#B_BL6ATj5*-1=C2QlsK#I&^$bJI=4w6+qnbt^F~EyQfu zLd@pP#56Y(vuP7C8#fZu)I^Ld6Vup8OhW@P_4UNm)e%!$OU#B1#MIOfQ(a9=RTVLn zmBdt35K~@GOj#K*rKQA_ln@gL5F<&%h$1n5KQTTZFbUD z|8L+3Wcdicn^}kD22qYiw*wI`x|`^`wL|b zbzE_L!2Uz~9m2E1d-!khA=_7N9oz-35k2I;eU*$1hmez2|I>%?of2PN<&)WEi~u9B zz61IXsbn~#Xd`L{RMZ$QAy>9eDijbil1!*ctfbl~7jkVhl_cPoc9jt| zoY7(7c-UUN9!8gnm?wLouZ1e@{NFCbJ3fzGOnkaa6rm(y{Ou z=zx+D{BJQTgj@#|0qW_9n#Kk4{O{F66&}lshm)yHIGV~Phr_C-rEn2YOD#=CQpsp+ zBv_OtcVz_QBo!h>p1ST5jGgY_XeyxwPbhjS8H8Hvgc`}{!I4;IG&>a36)lq*(UkP) zcs>bTw`Glkl~HxvLc;z3I&Lp=d7YntZw(l?|G_>cT$9EnPW*&_&Y$r8&Nu9R)_cJ7 zFTx4_Rqi=Yh*#Z@aC_ZNwxhPot_Qe3a%WcC?I2%Lx!Q}@{yN8-=u>O^RHIbLwNOb6 zQ1^|+BB~x7QX(gDodDUvY*xmSBVqG2#OD!%6LNMcnm`34q9Cr9!$a|`n$}{Z(S0+$ zRzd-bnowf#A`Ax%uaK*uf?-|*E}p`pN^&^9Fi!TbgBT^78N~%?B;U%NPap%-8WKh6 z0}^IGy-uO&vDNLuby{)y+()ljVU7{#xIrF{r$$B~VE~Jr^fGBdff@;GYE;$KWCXYC z%BVFhECp&rQ#1Ld75Km1@CmtEDjC!g5Yb}kOjyZ4*L(<*M zoV0c$8M+q9k9V9(X(yxc)TuD;AgjsYpc&1}4`dr$1L$y4)Uk9Rd#qkS#yu1zm?OG| zSO;NmqTz9&HL;|nXC5HKc}96H2o1;v(8Rs~AhC@Qhak?YOt8n#MMwT9!gt1jKF9u%ONr~nQ8I*=iW z7{`rR4hpE0FDsYv#nZY5Dg!}wib(YIqS2PIQp#n$*~&Oq0{%|W2>G(}SB5P>IYTTi zLLoigD*=OZG#Hr4alWbt-_MHR`&o*<<575PInbD&a4gMG zvxZu>hXwI|#sdh(DIzH9XHK{Q0+lLYg=ur$1%W?FBk)C`HaI5)dkx$4c!t!RkYCcf zu!=kNw30}}xFKFT0I`1F0TR}*Q@0uk_?m+McKZI46%$wlg#VlX5x<7@&1%A5lmxOo zc%NFkbay@Pi@Xinz}tgs?QM|t(m;WJuo9#!oTe&B>Hn{a|+YDbHB6Lq`<{3!bM#&zK(?Ube3gehd$5stbFKDV+M@>b^)Zll67%IKgLVTH%szoz4 zXLdnmp;GfMT^%&B697=DdCj)w;+f@%9?Ak1&tn?)9iV{92wx!$knUD~`Yyjr2G_*f zLB<-^#48saR!l6M-!^R9Kme7ofO!si2}LEAs~bdA&?p^>M39wA`8B)qQYJ#6gl5jL zdV+$sO%s}m+h{}jjfeO)N?%~D;*G4^J@)Lzc8p>`04OB*1%?8in`Ss-{ z+zoFlsH&xrTvk$5)aE&}l~!wG>3s6}763t|jucrY?6XNg1bN=7@BfcxXySz_% zcR>HY;ce^Mvj;N*i~u9R2rvSS03*N%{6!KlN{&FYmCBSyVIbuHdc)B`H-jcBgEMBA zn+(kqzd>er57X*f6tLvGo#8BgIi5`UYT0CxydGkd9Rf8}hG`0Fmh^S9Lhx7Qc%+u@{6;873(t4fw`@qHK!a|1WiX8AfGgj z-v4gLmwn&%^?D!k2H_omJKdMv$6P;l9sP@}qL?T~fDvE>7=as{0KNBY3svRHZSKSL z-bF5`vDy&U=)L*6d{Je7h~C#f7E~>5b01veua>ypDokr)lJtnoxfaJ-zp}p?0gDy_ zJJ*3h@j_ht8h>%wY7i97iVI_cky^u<>Far4dB=Gm3OaoJ++D)w0MbE+y4Up&;w)u diff --git a/src/spiffworkflow_backend/__init__.py b/src/spiffworkflow_backend/__init__.py index eef7eb18e..92c11037a 100644 --- a/src/spiffworkflow_backend/__init__.py +++ b/src/spiffworkflow_backend/__init__.py @@ -1,4 +1,5 @@ """__init__.""" +import faulthandler import os from typing import Any @@ -9,17 +10,16 @@ import sqlalchemy from apscheduler.schedulers.background import BackgroundScheduler # type: ignore from apscheduler.schedulers.base import BaseScheduler # type: ignore from flask.json.provider import DefaultJSONProvider -from flask_bpmn.api.api_error import api_error_blueprint -from flask_bpmn.models.db import db -from flask_bpmn.models.db import migrate from flask_cors import CORS # type: ignore from flask_mail import Mail # type: ignore from werkzeug.exceptions import NotFound import spiffworkflow_backend.load_database_models # noqa: F401 from spiffworkflow_backend.config import setup_config +from spiffworkflow_backend.exceptions.api_error import api_error_blueprint from spiffworkflow_backend.helpers.api_version import V1_API_PATH_PREFIX -from spiffworkflow_backend.routes.admin_blueprint.admin_blueprint import admin_blueprint +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import migrate from spiffworkflow_backend.routes.openid_blueprint.openid_blueprint import ( openid_blueprint, ) @@ -80,6 +80,8 @@ def start_scheduler( def create_app() -> flask.app.Flask: """Create_app.""" + faulthandler.enable() + # We need to create the sqlite database in a known location. # If we rely on the app.instance_path without setting an environment # variable, it will be one thing when we run flask db upgrade in the @@ -106,7 +108,6 @@ def create_app() -> flask.app.Flask: app.register_blueprint(user_blueprint) app.register_blueprint(api_error_blueprint) - app.register_blueprint(admin_blueprint, url_prefix="/admin") app.register_blueprint(openid_blueprint, url_prefix="/openid") # preflight options requests will be allowed if they meet the requirements of the url regex. @@ -114,7 +115,7 @@ def create_app() -> flask.app.Flask: # need to continually keep asking for the same path. origins_re = [ r"^https?:\/\/%s(.*)" % o.replace(".", r"\.") - for o in app.config["CORS_ALLOW_ORIGINS"] + for o in app.config["SPIFFWORKFLOW_BACKEND_CORS_ALLOW_ORIGINS"] ] CORS(app, origins=origins_re, max_age=3600, supports_credentials=True) @@ -127,7 +128,7 @@ def create_app() -> flask.app.Flask: # do not start the scheduler twice in flask debug mode if ( - app.config["RUN_BACKGROUND_SCHEDULER"] + app.config["SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER"] and os.environ.get("WERKZEUG_RUN_MAIN") != "true" ): start_scheduler(app) @@ -143,22 +144,47 @@ def create_app() -> flask.app.Flask: def get_hacked_up_app_for_script() -> flask.app.Flask: """Get_hacked_up_app_for_script.""" - os.environ["SPIFFWORKFLOW_BACKEND_ENV"] = "development" + os.environ["SPIFFWORKFLOW_BACKEND_ENV"] = "local_development" flask_env_key = "FLASK_SESSION_SECRET_KEY" os.environ[flask_env_key] = "whatevs" - if "BPMN_SPEC_ABSOLUTE_DIR" not in os.environ: + if "SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR" not in os.environ: home = os.environ["HOME"] full_process_model_path = ( f"{home}/projects/github/sartography/sample-process-models" ) if os.path.isdir(full_process_model_path): - os.environ["BPMN_SPEC_ABSOLUTE_DIR"] = full_process_model_path + os.environ["SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR"] = ( + full_process_model_path + ) else: raise Exception(f"Could not find {full_process_model_path}") app = create_app() return app +def traces_sampler(sampling_context: Any) -> Any: + # always inherit + if sampling_context["parent_sampled"] is not None: + return sampling_context["parent_sampled"] + + if "wsgi_environ" in sampling_context: + wsgi_environ = sampling_context["wsgi_environ"] + path_info = wsgi_environ.get("PATH_INFO") + request_method = wsgi_environ.get("REQUEST_METHOD") + + # tasks_controller.task_submit + # this is the current pain point as of 31 jan 2023. + if ( + path_info + and path_info.startswith("/v1.0/tasks/") + and request_method == "PUT" + ): + return 1 + + # Default sample rate for all others (replaces traces_sample_rate) + return 0.01 + + def configure_sentry(app: flask.app.Flask) -> None: """Configure_sentry.""" import sentry_sdk @@ -174,16 +200,28 @@ def configure_sentry(app: flask.app.Flask) -> None: return None return event - sentry_errors_sample_rate = app.config.get("SENTRY_ERRORS_SAMPLE_RATE") + sentry_errors_sample_rate = app.config.get( + "SPIFFWORKFLOW_BACKEND_SENTRY_ERRORS_SAMPLE_RATE" + ) if sentry_errors_sample_rate is None: - raise Exception("SENTRY_ERRORS_SAMPLE_RATE is not set somehow") + raise Exception( + "SPIFFWORKFLOW_BACKEND_SENTRY_ERRORS_SAMPLE_RATE is not set somehow" + ) - sentry_traces_sample_rate = app.config.get("SENTRY_TRACES_SAMPLE_RATE") + sentry_traces_sample_rate = app.config.get( + "SPIFFWORKFLOW_BACKEND_SENTRY_TRACES_SAMPLE_RATE" + ) if sentry_traces_sample_rate is None: - raise Exception("SENTRY_TRACES_SAMPLE_RATE is not set somehow") + raise Exception( + "SPIFFWORKFLOW_BACKEND_SENTRY_TRACES_SAMPLE_RATE is not set somehow" + ) + + # profiling doesn't work on windows, because of an issue like https://github.com/nvdv/vprof/issues/62 + # but also we commented out profiling because it was causing segfaults (i guess it is marked experimental) + # profiles_sample_rate = 0 if sys.platform.startswith("win") else 1 sentry_sdk.init( - dsn=app.config.get("SENTRY_DSN"), + dsn=app.config.get("SPIFFWORKFLOW_BACKEND_SENTRY_DSN"), integrations=[ FlaskIntegration(), ], @@ -195,5 +233,8 @@ def configure_sentry(app: flask.app.Flask) -> None: # of transactions for performance monitoring. # We recommend adjusting this value to less than 1(00%) in production. traces_sample_rate=float(sentry_traces_sample_rate), + traces_sampler=traces_sampler, + # The profiles_sample_rate setting is relative to the traces_sample_rate setting. + # _experiments={"profiles_sample_rate": profiles_sample_rate}, before_send=before_send, ) diff --git a/src/spiffworkflow_backend/api.yml b/src/spiffworkflow_backend/api.yml index 825a24b4a..842491c24 100755 --- a/src/spiffworkflow_backend/api.yml +++ b/src/spiffworkflow_backend/api.yml @@ -79,6 +79,26 @@ paths: "200": description: Logout Authenticated User + /login_with_access_token: + parameters: + - name: access_token + in: query + required: true + schema: + type: string + post: + operationId: spiffworkflow_backend.routes.user.login_with_access_token + summary: Authenticate user for API access with an openid token already posessed. + tags: + - Authentication + responses: + "200": + description: "Returns ok: true if user successfully logged in." + content: + application/json: + schema: + $ref: "#/components/schemas/OkTrue" + /login_api: get: operationId: spiffworkflow_backend.routes.user.login_api @@ -1605,6 +1625,45 @@ paths: schema: $ref: "#/components/schemas/Workflow" + /process-data-file-download/{modified_process_model_identifier}/{process_instance_id}/{process_data_identifier}: + parameters: + - name: modified_process_model_identifier + in: path + required: true + description: The modified id of an existing process model + schema: + type: string + - name: process_instance_id + in: path + required: true + description: The unique id of an existing process instance. + schema: + type: integer + - name: process_data_identifier + in: path + required: true + description: The identifier of the process data. + schema: + type: string + - name: index + in: query + required: false + description: The optional index of the value if key's value is an array + schema: + type: integer + get: + operationId: spiffworkflow_backend.routes.process_api_blueprint.process_data_file_download + summary: Download the file referneced in the process data value. + tags: + - Data Objects + responses: + "200": + description: Fetch succeeded. + content: + application/json: + schema: + $ref: "#/components/schemas/Workflow" + /send-event/{modified_process_model_identifier}/{process_instance_id}: parameters: - name: modified_process_model_identifier diff --git a/src/spiffworkflow_backend/config/__init__.py b/src/spiffworkflow_backend/config/__init__.py index 7d915946b..ad5dcb0f5 100644 --- a/src/spiffworkflow_backend/config/__init__.py +++ b/src/spiffworkflow_backend/config/__init__.py @@ -1,6 +1,7 @@ """__init__.py.""" import os import threading +import uuid from flask.app import Flask from werkzeug.utils import ImportStringError @@ -16,17 +17,17 @@ def setup_database_uri(app: Flask) -> None: """Setup_database_uri.""" if app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_URI") is None: database_name = f"spiffworkflow_backend_{app.config['ENV_IDENTIFIER']}" - if app.config.get("SPIFF_DATABASE_TYPE") == "sqlite": + if app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_TYPE") == "sqlite": app.config["SQLALCHEMY_DATABASE_URI"] = ( f"sqlite:///{app.instance_path}/db_{app.config['ENV_IDENTIFIER']}.sqlite3" ) - elif app.config.get("SPIFF_DATABASE_TYPE") == "postgres": + elif app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_TYPE") == "postgres": app.config["SQLALCHEMY_DATABASE_URI"] = ( f"postgresql://spiffworkflow_backend:spiffworkflow_backend@localhost:5432/{database_name}" ) else: # use pswd to trick flake8 with hardcoded passwords - db_pswd = os.environ.get("DB_PASSWORD") + db_pswd = app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_PASSWORD") if db_pswd is None: db_pswd = "" app.config["SQLALCHEMY_DATABASE_URI"] = ( @@ -44,12 +45,33 @@ def load_config_file(app: Flask, env_config_module: str) -> None: app.config.from_object(env_config_module) print(f"loaded config: {env_config_module}") except ImportStringError as exception: - if os.environ.get("TERRAFORM_DEPLOYED_ENVIRONMENT") != "true": + if ( + os.environ.get("SPIFFWORKFLOW_BACKEND_TERRAFORM_DEPLOYED_ENVIRONMENT") + != "true" + ): raise ModuleNotFoundError( f"Cannot find config module: {env_config_module}" ) from exception +def _set_up_tenant_specific_fields_as_list_of_strings(app: Flask) -> None: + tenant_specific_fields = app.config.get( + "SPIFFWORKFLOW_BACKEND_OPEN_ID_TENANT_SPECIFIC_FIELDS" + ) + + if tenant_specific_fields is None or tenant_specific_fields == "": + app.config["SPIFFWORKFLOW_BACKEND_OPEN_ID_TENANT_SPECIFIC_FIELDS"] = [] + else: + app.config["SPIFFWORKFLOW_BACKEND_OPEN_ID_TENANT_SPECIFIC_FIELDS"] = ( + tenant_specific_fields.split(",") + ) + if len(app.config["SPIFFWORKFLOW_BACKEND_OPEN_ID_TENANT_SPECIFIC_FIELDS"]) > 3: + raise ConfigurationError( + "SPIFFWORKFLOW_BACKEND_OPEN_ID_TENANT_SPECIFIC_FIELDS can have a" + " maximum of 3 fields" + ) + + def setup_config(app: Flask) -> None: """Setup_config.""" # ensure the instance folder exists @@ -59,14 +81,14 @@ def setup_config(app: Flask) -> None: pass app.config["ENV_IDENTIFIER"] = os.environ.get( - "SPIFFWORKFLOW_BACKEND_ENV", "development" + "SPIFFWORKFLOW_BACKEND_ENV", "local_development" ) app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False - app.config.from_object("spiffworkflow_backend.config.default") + load_config_file(app, "spiffworkflow_backend.config.default") env_config_prefix = "spiffworkflow_backend.config." if ( - os.environ.get("TERRAFORM_DEPLOYED_ENVIRONMENT") == "true" + os.environ.get("SPIFFWORKFLOW_BACKEND_TERRAFORM_DEPLOYED_ENVIRONMENT") == "true" and os.environ.get("SPIFFWORKFLOW_BACKEND_ENV") is not None ): load_config_file(app, f"{env_config_prefix}terraform_deployed_environment") @@ -77,27 +99,44 @@ def setup_config(app: Flask) -> None: # This allows config/testing.py or instance/config.py to override the default config if "ENV_IDENTIFIER" in app.config and app.config["ENV_IDENTIFIER"] == "testing": app.config.from_pyfile("config/testing.py", silent=True) + elif ( + "ENV_IDENTIFIER" in app.config + and app.config["ENV_IDENTIFIER"] == "unit_testing" + ): + app.config.from_pyfile("config/unit_testing.py", silent=True) else: app.config.from_pyfile(f"{app.instance_path}/config.py", silent=True) app.config["PERMISSIONS_FILE_FULLPATH"] = None - if app.config["SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME"]: + permissions_file_name = app.config["SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME"] + if permissions_file_name is not None: app.config["PERMISSIONS_FILE_FULLPATH"] = os.path.join( app.root_path, "config", "permissions", - app.config["SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME"], + permissions_file_name, ) + print(f"base_permissions: loaded permissions file: {permissions_file_name}") + else: + print("base_permissions: no permissions file loaded") # unversioned (see .gitignore) config that can override everything and include secrets. # src/spiffworkflow_backend/config/secrets.py app.config.from_pyfile(os.path.join("config", "secrets.py"), silent=True) - if app.config["BPMN_SPEC_ABSOLUTE_DIR"] is None: - raise ConfigurationError("BPMN_SPEC_ABSOLUTE_DIR config must be set") + if app.config["SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR"] is None: + raise ConfigurationError( + "SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR config must be set" + ) + + app.config["PROCESS_UUID"] = uuid.uuid4() setup_database_uri(app) setup_logger(app) + if app.config["SPIFFWORKFLOW_BACKEND_DEFAULT_USER_GROUP"] == "": + app.config["SPIFFWORKFLOW_BACKEND_DEFAULT_USER_GROUP"] = None + thread_local_data = threading.local() app.config["THREAD_LOCAL_DATA"] = thread_local_data + _set_up_tenant_specific_fields_as_list_of_strings(app) diff --git a/src/spiffworkflow_backend/config/default.py b/src/spiffworkflow_backend/config/default.py index 80cfb9191..a08ef3e01 100644 --- a/src/spiffworkflow_backend/config/default.py +++ b/src/spiffworkflow_backend/config/default.py @@ -2,45 +2,57 @@ import re from os import environ -# Does the site allow self-registration of users -SELF_REGISTRATION = environ.get("SELF_REGISTRATION", default=False) +# Consider: https://flask.palletsprojects.com/en/2.2.x/config/#configuring-from-environment-variables +# and from_prefixed_env(), though we want to ensure that these variables are all documented, so that +# is a benefit of the status quo and having them all in this file explicitly. -DEVELOPMENT = False - -BPMN_SPEC_ABSOLUTE_DIR = environ.get("BPMN_SPEC_ABSOLUTE_DIR") -CORS_DEFAULT = "*" -CORS_ALLOW_ORIGINS = re.split( - r",\s*", environ.get("CORS_ALLOW_ORIGINS", default=CORS_DEFAULT) +SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR = environ.get( + "SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR" +) +cors_allow_all = "*" +SPIFFWORKFLOW_BACKEND_CORS_ALLOW_ORIGINS = re.split( + r",\s*", + environ.get("SPIFFWORKFLOW_BACKEND_CORS_ALLOW_ORIGINS", default=cors_allow_all), ) -RUN_BACKGROUND_SCHEDULER = ( - environ.get("RUN_BACKGROUND_SCHEDULER", default="false") == "true" +SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER = ( + environ.get("SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER", default="false") + == "true" ) -SPIFFWORKFLOW_FRONTEND_URL = environ.get( - "SPIFFWORKFLOW_FRONTEND_URL", default="http://localhost:7001" +SPIFFWORKFLOW_BACKEND_URL_FOR_FRONTEND = environ.get( + "SPIFFWORKFLOW_BACKEND_URL_FOR_FRONTEND", default="http://localhost:7001" ) SPIFFWORKFLOW_BACKEND_URL = environ.get( "SPIFFWORKFLOW_BACKEND_URL", default="http://localhost:7000" ) # service task connector proxy -CONNECTOR_PROXY_URL = environ.get( - "CONNECTOR_PROXY_URL", default="http://localhost:7004" +SPIFFWORKFLOW_BACKEND_CONNECTOR_PROXY_URL = environ.get( + "SPIFFWORKFLOW_BACKEND_CONNECTOR_PROXY_URL", default="http://localhost:7004" ) # Open ID server -OPEN_ID_SERVER_URL = environ.get( - "OPEN_ID_SERVER_URL", - default="http://localhost:7002/realms/spiffworkflow" - # "OPEN_ID_SERVER_URL", default="http://localhost:7000/openid" +# use "http://localhost:7000/openid" for running with simple openid +# server hosted by spiffworkflow-backend +SPIFFWORKFLOW_BACKEND_OPEN_ID_SERVER_URL = environ.get( + "SPIFFWORKFLOW_BACKEND_OPEN_ID_SERVER_URL", + default="http://localhost:7002/realms/spiffworkflow", ) -# Replace above line with this to use the built-in Open ID Server. -# OPEN_ID_SERVER_URL = environ.get("OPEN_ID_SERVER_URL", default="http://localhost:7000/openid") -OPEN_ID_CLIENT_ID = environ.get("OPEN_ID_CLIENT_ID", default="spiffworkflow-backend") -OPEN_ID_CLIENT_SECRET_KEY = environ.get( - "OPEN_ID_CLIENT_SECRET_KEY", default="JXeQExm0JhQPLumgHtIIqf52bDalHz0q" +SPIFFWORKFLOW_BACKEND_OPEN_ID_CLIENT_ID = environ.get( + "SPIFFWORKFLOW_BACKEND_OPEN_ID_CLIENT_ID", default="spiffworkflow-backend" +) +SPIFFWORKFLOW_BACKEND_OPEN_ID_CLIENT_SECRET_KEY = environ.get( + "SPIFFWORKFLOW_BACKEND_OPEN_ID_CLIENT_SECRET_KEY", + default="JXeQExm0JhQPLumgHtIIqf52bDalHz0q", ) # noqa: S105 +# Tenant specific fields is a comma separated list of field names that we will convert to list of strings +# and store in the user table's tenant_specific_field_n columns. You can have up to three items in this +# comma-separated list. +SPIFFWORKFLOW_BACKEND_OPEN_ID_TENANT_SPECIFIC_FIELDS = environ.get( + "SPIFFWORKFLOW_BACKEND_OPEN_ID_TENANT_SPECIFIC_FIELDS" +) + SPIFFWORKFLOW_BACKEND_LOG_TO_FILE = ( environ.get("SPIFFWORKFLOW_BACKEND_LOG_TO_FILE", default="false") == "true" ) @@ -50,13 +62,21 @@ SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME = environ.get( ) # Sentry Configuration -SENTRY_DSN = environ.get("SENTRY_DSN", default="") -SENTRY_ERRORS_SAMPLE_RATE = environ.get( - "SENTRY_ERRORS_SAMPLE_RATE", default="1" +SPIFFWORKFLOW_BACKEND_SENTRY_DSN = environ.get( + "SPIFFWORKFLOW_BACKEND_SENTRY_DSN", default="" +) +SPIFFWORKFLOW_BACKEND_SENTRY_ERRORS_SAMPLE_RATE = environ.get( + "SPIFFWORKFLOW_BACKEND_SENTRY_ERRORS_SAMPLE_RATE", default="1" ) # send all errors -SENTRY_TRACES_SAMPLE_RATE = environ.get( - "SENTRY_TRACES_SAMPLE_RATE", default="0.01" +SPIFFWORKFLOW_BACKEND_SENTRY_TRACES_SAMPLE_RATE = environ.get( + "SPIFFWORKFLOW_BACKEND_SENTRY_TRACES_SAMPLE_RATE", default="0.01" ) # send 1% of traces +SPIFFWORKFLOW_BACKEND_SENTRY_ORGANIZATION_SLUG = environ.get( + "SPIFFWORKFLOW_BACKEND_SENTRY_ORGANIZATION_SLUG", default=None +) +SPIFFWORKFLOW_BACKEND_SENTRY_PROJECT_SLUG = environ.get( + "SPIFFWORKFLOW_BACKEND_SENTRY_PROJECT_SLUG", default=None +) SPIFFWORKFLOW_BACKEND_LOG_LEVEL = environ.get( "SPIFFWORKFLOW_BACKEND_LOG_LEVEL", default="info" @@ -64,20 +84,57 @@ SPIFFWORKFLOW_BACKEND_LOG_LEVEL = environ.get( # When a user clicks on the `Publish` button, this is the default branch this server merges into. # I.e., dev server could have `staging` here. Staging server might have `production` here. -GIT_BRANCH_TO_PUBLISH_TO = environ.get("GIT_BRANCH_TO_PUBLISH_TO") -GIT_BRANCH = environ.get("GIT_BRANCH") -GIT_CLONE_URL_FOR_PUBLISHING = environ.get("GIT_CLONE_URL") -GIT_COMMIT_ON_SAVE = environ.get("GIT_COMMIT_ON_SAVE", default="false") == "true" +SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_TARGET_BRANCH = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_TARGET_BRANCH" +) +# This is the branch that the app automatically commits to every time the user clicks the save button +# or otherwise changes a process model. +# If publishing is enabled, the contents of this "staging area" / "scratch pad" / WIP spot will be used +# as the relevant contents for process model that the user wants to publish. +SPIFFWORKFLOW_BACKEND_GIT_SOURCE_BRANCH = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_SOURCE_BRANCH" +) +SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL" +) +SPIFFWORKFLOW_BACKEND_GIT_COMMIT_ON_SAVE = ( + environ.get("SPIFFWORKFLOW_BACKEND_GIT_COMMIT_ON_SAVE", default="false") == "true" +) +SPIFFWORKFLOW_BACKEND_GIT_USERNAME = environ.get("SPIFFWORKFLOW_BACKEND_GIT_USERNAME") +SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL" +) +SPIFFWORKFLOW_BACKEND_GITHUB_WEBHOOK_SECRET = environ.get( + "SPIFFWORKFLOW_BACKEND_GITHUB_WEBHOOK_SECRET", default=None +) +SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_SSH_PRIVATE_KEY_PATH", default=None +) -# Datbase Configuration -SPIFF_DATABASE_TYPE = environ.get( - "SPIFF_DATABASE_TYPE", default="mysql" +# Database Configuration +SPIFFWORKFLOW_BACKEND_DATABASE_TYPE = environ.get( + "SPIFFWORKFLOW_BACKEND_DATABASE_TYPE", default="mysql" ) # can also be sqlite, postgres # Overide above with specific sqlalchymy connection string. SPIFFWORKFLOW_BACKEND_DATABASE_URI = environ.get( "SPIFFWORKFLOW_BACKEND_DATABASE_URI", default=None ) -SYSTEM_NOTIFICATION_PROCESS_MODEL_MESSAGE_ID = environ.get( - "SYSTEM_NOTIFICATION_PROCESS_MODEL_MESSAGE_ID", +SPIFFWORKFLOW_BACKEND_SYSTEM_NOTIFICATION_PROCESS_MODEL_MESSAGE_ID = environ.get( + "SPIFFWORKFLOW_BACKEND_SYSTEM_NOTIFICATION_PROCESS_MODEL_MESSAGE_ID", default="Message_SystemMessageNotification", ) + +SPIFFWORKFLOW_BACKEND_ALLOW_CONFISCATING_LOCK_AFTER_SECONDS = int( + environ.get( + "SPIFFWORKFLOW_BACKEND_ALLOW_CONFISCATING_LOCK_AFTER_SECONDS", default="600" + ) +) + +SPIFFWORKFLOW_BACKEND_DEFAULT_USER_GROUP = environ.get( + "SPIFFWORKFLOW_BACKEND_DEFAULT_USER_GROUP", default="everybody" +) + +# this is only used in CI. use SPIFFWORKFLOW_BACKEND_DATABASE_URI instead for real configuration +SPIFFWORKFLOW_BACKEND_DATABASE_PASSWORD = environ.get( + "SPIFFWORKFLOW_BACKEND_DATABASE_PASSWORD", default=None +) diff --git a/src/spiffworkflow_backend/config/demo.py b/src/spiffworkflow_backend/config/demo.py index 06e9184d7..aec6a03bb 100644 --- a/src/spiffworkflow_backend/config/demo.py +++ b/src/spiffworkflow_backend/config/demo.py @@ -1,14 +1,15 @@ """Demo environment.""" from os import environ -GIT_COMMIT_ON_SAVE = True -GIT_USERNAME = "demo" -GIT_USER_EMAIL = "demo@example.com" +SPIFFWORKFLOW_BACKEND_GIT_COMMIT_ON_SAVE = True +SPIFFWORKFLOW_BACKEND_GIT_USERNAME = "demo" +SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL = "demo@example.com" SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME = environ.get( "SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME", default="terraform_deployed_environment.yml", ) -RUN_BACKGROUND_SCHEDULER = ( - environ.get("RUN_BACKGROUND_SCHEDULER", default="false") == "true" +SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER = ( + environ.get("SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER", default="false") + == "true" ) diff --git a/src/spiffworkflow_backend/config/dev.py b/src/spiffworkflow_backend/config/dev.py index cbbc269a8..ef0250604 100644 --- a/src/spiffworkflow_backend/config/dev.py +++ b/src/spiffworkflow_backend/config/dev.py @@ -1,9 +1,14 @@ """Dev.""" from os import environ -GIT_BRANCH_TO_PUBLISH_TO = environ.get("GIT_BRANCH_TO_PUBLISH_TO", default="staging") -GIT_USERNAME = environ.get("GIT_USERNAME", default="sartography-automated-committer") -GIT_USER_EMAIL = environ.get( - "GIT_USER_EMAIL", default="sartography-automated-committer@users.noreply.github.com" +SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_TARGET_BRANCH = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_TARGET_BRANCH", default="staging" +) +SPIFFWORKFLOW_BACKEND_GIT_USERNAME = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_USERNAME", default="sartography-automated-committer" +) +SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL", + default="sartography-automated-committer@users.noreply.github.com", ) SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME = "dev.yml" diff --git a/src/spiffworkflow_backend/config/development.py b/src/spiffworkflow_backend/config/development.py deleted file mode 100644 index b1ea980c2..000000000 --- a/src/spiffworkflow_backend/config/development.py +++ /dev/null @@ -1,19 +0,0 @@ -"""Development.""" -from os import environ - -SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME = environ.get( - "SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME", default="development.yml" -) - -SPIFFWORKFLOW_BACKEND_LOG_LEVEL = environ.get( - "SPIFFWORKFLOW_BACKEND_LOG_LEVEL", default="debug" -) - -RUN_BACKGROUND_SCHEDULER = ( - 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" -) -GIT_USERNAME = "sartography-automated-committer" -GIT_USER_EMAIL = f"{GIT_USERNAME}@users.noreply.github.com" diff --git a/src/spiffworkflow_backend/config/local_development.py b/src/spiffworkflow_backend/config/local_development.py new file mode 100644 index 000000000..197637b4e --- /dev/null +++ b/src/spiffworkflow_backend/config/local_development.py @@ -0,0 +1,23 @@ +"""Development.""" +from os import environ + +SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME = environ.get( + "SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME", default="local_development.yml" +) + +SPIFFWORKFLOW_BACKEND_LOG_LEVEL = environ.get( + "SPIFFWORKFLOW_BACKEND_LOG_LEVEL", default="debug" +) + +SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER = ( + environ.get("SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER", default="false") + == "true" +) +SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL", + default="https://github.com/sartography/sample-process-models.git", +) +SPIFFWORKFLOW_BACKEND_GIT_USERNAME = "sartography-automated-committer" +SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL = ( + f"{SPIFFWORKFLOW_BACKEND_GIT_USERNAME}@users.noreply.github.com" +) diff --git a/src/spiffworkflow_backend/config/permissions/example.yml b/src/spiffworkflow_backend/config/permissions/example.yml index 248a400b4..048f9de64 100644 --- a/src/spiffworkflow_backend/config/permissions/example.yml +++ b/src/spiffworkflow_backend/config/permissions/example.yml @@ -16,6 +16,12 @@ users: email: malala@spiffworkflow.org password: malala preferred_username: Malala + oskar: + service: local_open_id + email: oskar@spiffworkflow.org + password: oskar + preferred_username: Oskar + groups: admin: @@ -23,16 +29,6 @@ groups: [ admin@spiffworkflow.org, ] - Education: - users: - [ - malala@spiffworkflow.org - ] - President: - users: - [ - nelson@spiffworkflow.org - ] permissions: # Admins have access to everything. @@ -75,16 +71,8 @@ permissions: users: [ ] allowed_permissions: [ read ] uri: /processes - # Members of the Education group can change the processes under "education". - education-admin: - groups: ["Education", "President"] - users: [] - allowed_permissions: [create, read, update, delete] - uri: /process-groups/education:* - - # Anyone can start an education process. - education-everybody: + groups-everybody: groups: [everybody] users: [] allowed_permissions: [create, read] - uri: /process-instances/misc:category_number_one:process-model-with-form/* + uri: /v1.0/user-groups/for-current-user diff --git a/src/spiffworkflow_backend/config/permissions/development.yml b/src/spiffworkflow_backend/config/permissions/local_development.yml similarity index 100% rename from src/spiffworkflow_backend/config/permissions/development.yml rename to src/spiffworkflow_backend/config/permissions/local_development.yml diff --git a/src/spiffworkflow_backend/config/permissions/testing.yml b/src/spiffworkflow_backend/config/permissions/unit_testing.yml similarity index 100% rename from src/spiffworkflow_backend/config/permissions/testing.yml rename to src/spiffworkflow_backend/config/permissions/unit_testing.yml diff --git a/src/spiffworkflow_backend/config/qa1.py b/src/spiffworkflow_backend/config/qa1.py index 2f8ad5fca..ac56d84f1 100644 --- a/src/spiffworkflow_backend/config/qa1.py +++ b/src/spiffworkflow_backend/config/qa1.py @@ -1,10 +1,15 @@ """Qa1.""" from os import environ -GIT_BRANCH_TO_PUBLISH_TO = environ.get("GIT_BRANCH_TO_PUBLISH_TO", default="qa2") -GIT_USERNAME = environ.get("GIT_USERNAME", default="sartography-automated-committer") -GIT_USER_EMAIL = environ.get( - "GIT_USER_EMAIL", default="sartography-automated-committer@users.noreply.github.com" +SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_TARGET_BRANCH = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_TARGET_BRANCH", default="qa2" +) +SPIFFWORKFLOW_BACKEND_GIT_USERNAME = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_USERNAME", default="sartography-automated-committer" +) +SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL", + default=f"{SPIFFWORKFLOW_BACKEND_GIT_USERNAME}@users.noreply.github.com", ) SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME = environ.get( "SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME", default="qa1.yml" diff --git a/src/spiffworkflow_backend/config/qa2.py b/src/spiffworkflow_backend/config/qa2.py new file mode 100644 index 000000000..f81d88645 --- /dev/null +++ b/src/spiffworkflow_backend/config/qa2.py @@ -0,0 +1,14 @@ +"""Qa2.""" +from os import environ + +SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME = environ.get( + "SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME", default="qa1.yml" +) +SPIFFWORKFLOW_BACKEND_URL_FOR_FRONTEND = "https://qa2.spiffworkflow.org" +SPIFFWORKFLOW_BACKEND_OPEN_ID_SERVER_URL = ( + "https://qa2.spiffworkflow.org/keycloak/realms/spiffworkflow" +) +SPIFFWORKFLOW_BACKEND_URL = "https://qa2.spiffworkflow.org/api" +SPIFFWORKFLOW_BACKEND_CONNECTOR_PROXY_URL = ( + "https://qa2.spiffworkflow.org/connector-proxy" +) diff --git a/src/spiffworkflow_backend/config/sartography.py b/src/spiffworkflow_backend/config/sartography.py new file mode 100644 index 000000000..083684742 --- /dev/null +++ b/src/spiffworkflow_backend/config/sartography.py @@ -0,0 +1,15 @@ +"""Default.""" +from os import environ + +environment_identifier_for_this_config_file_only = environ["SPIFFWORKFLOW_BACKEND_ENV"] +SPIFFWORKFLOW_BACKEND_OPEN_ID_SERVER_URL = ( + f"https://keycloak.{environment_identifier_for_this_config_file_only}" + ".spiffworkflow.org/realms/sartography" +) +SPIFFWORKFLOW_BACKEND_GIT_SOURCE_BRANCH = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_SOURCE_BRANCH", default="main" +) +SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL", + default="https://github.com/sartography/sartography-process-models.git", +) diff --git a/src/spiffworkflow_backend/config/staging.py b/src/spiffworkflow_backend/config/staging.py index 807163315..edfe36d79 100644 --- a/src/spiffworkflow_backend/config/staging.py +++ b/src/spiffworkflow_backend/config/staging.py @@ -1,7 +1,11 @@ """Staging.""" from os import environ -GIT_BRANCH = environ.get("GIT_BRANCH", default="staging") -GIT_BRANCH_TO_PUBLISH_TO = environ.get("GIT_BRANCH_TO_PUBLISH_TO", default="main") -GIT_COMMIT_ON_SAVE = False +SPIFFWORKFLOW_BACKEND_GIT_SOURCE_BRANCH = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_SOURCE_BRANCH", default="staging" +) +SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_TARGET_BRANCH = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_TARGET_BRANCH", default="main" +) +SPIFFWORKFLOW_BACKEND_GIT_COMMIT_ON_SAVE = False SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME = "staging.yml" diff --git a/src/spiffworkflow_backend/config/terraform_deployed_environment.py b/src/spiffworkflow_backend/config/terraform_deployed_environment.py index efd451834..b3e5a1130 100644 --- a/src/spiffworkflow_backend/config/terraform_deployed_environment.py +++ b/src/spiffworkflow_backend/config/terraform_deployed_environment.py @@ -4,26 +4,36 @@ from os import environ # default.py already ensured that this key existed as was not None environment_identifier_for_this_config_file_only = environ["SPIFFWORKFLOW_BACKEND_ENV"] -GIT_COMMIT_ON_SAVE = True -GIT_USERNAME = "sartography-automated-committer" -GIT_USER_EMAIL = f"{GIT_USERNAME}@users.noreply.github.com" +SPIFFWORKFLOW_BACKEND_GIT_COMMIT_ON_SAVE = True +SPIFFWORKFLOW_BACKEND_GIT_USERNAME = "sartography-automated-committer" +SPIFFWORKFLOW_BACKEND_GIT_USER_EMAIL = ( + f"{SPIFFWORKFLOW_BACKEND_GIT_USERNAME}@users.noreply.github.com" +) SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME = environ.get( "SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME", default="terraform_deployed_environment.yml", ) -RUN_BACKGROUND_SCHEDULER = ( - environ.get("RUN_BACKGROUND_SCHEDULER", default="false") == "true" +SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER = ( + environ.get("SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER", default="false") + == "true" ) -OPEN_ID_SERVER_URL = f"https://keycloak.{environment_identifier_for_this_config_file_only}.spiffworkflow.org/realms/spiffworkflow" -SPIFFWORKFLOW_FRONTEND_URL = ( +SPIFFWORKFLOW_BACKEND_OPEN_ID_SERVER_URL = ( + f"https://keycloak.{environment_identifier_for_this_config_file_only}" + ".spiffworkflow.org/realms/spiffworkflow" +) +SPIFFWORKFLOW_BACKEND_URL_FOR_FRONTEND = ( f"https://{environment_identifier_for_this_config_file_only}.spiffworkflow.org" ) SPIFFWORKFLOW_BACKEND_URL = ( f"https://api.{environment_identifier_for_this_config_file_only}.spiffworkflow.org" ) -CONNECTOR_PROXY_URL = f"https://connector-proxy.{environment_identifier_for_this_config_file_only}.spiffworkflow.org" -GIT_CLONE_URL_FOR_PUBLISHING = environ.get( - "GIT_CLONE_URL", default="https://github.com/sartography/sample-process-models.git" +SPIFFWORKFLOW_BACKEND_CONNECTOR_PROXY_URL = ( + f"https://connector-proxy.{environment_identifier_for_this_config_file_only}" + ".spiffworkflow.org" +) +SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL = environ.get( + "SPIFFWORKFLOW_BACKEND_GIT_PUBLISH_CLONE_URL", + default="https://github.com/sartography/sample-process-models.git", ) diff --git a/src/spiffworkflow_backend/config/testing.py b/src/spiffworkflow_backend/config/unit_testing.py similarity index 77% rename from src/spiffworkflow_backend/config/testing.py rename to src/spiffworkflow_backend/config/unit_testing.py index 605c1bccc..e486fe769 100644 --- a/src/spiffworkflow_backend/config/testing.py +++ b/src/spiffworkflow_backend/config/unit_testing.py @@ -9,17 +9,17 @@ SPIFFWORKFLOW_BACKEND_LOG_TO_FILE = ( ) SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME = environ.get( - "SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME", default="testing.yml" + "SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME", default="unit_testing.yml" ) SPIFFWORKFLOW_BACKEND_LOG_LEVEL = environ.get( "SPIFFWORKFLOW_BACKEND_LOG_LEVEL", default="debug" ) -GIT_COMMIT_ON_SAVE = False +SPIFFWORKFLOW_BACKEND_GIT_COMMIT_ON_SAVE = False # NOTE: set this here since nox shoves tests and src code to # different places and this allows us to know exactly where we are at the start -BPMN_SPEC_ABSOLUTE_DIR = os.path.join( +SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR = os.path.join( os.path.dirname(__file__), "..", "..", diff --git a/src/spiffworkflow_backend/exceptions/api_error.py b/src/spiffworkflow_backend/exceptions/api_error.py new file mode 100644 index 000000000..5fff05c2d --- /dev/null +++ b/src/spiffworkflow_backend/exceptions/api_error.py @@ -0,0 +1,261 @@ +"""API Error functionality.""" +from __future__ import annotations + +import json +from dataclasses import dataclass +from dataclasses import field +from typing import Any + +import flask.wrappers +import sentry_sdk +from flask import Blueprint +from flask import current_app +from flask import g +from flask import jsonify +from flask import make_response +from sentry_sdk import capture_exception +from sentry_sdk import set_tag +from SpiffWorkflow.exceptions import SpiffWorkflowException # type: ignore +from SpiffWorkflow.exceptions import WorkflowException +from SpiffWorkflow.exceptions import WorkflowTaskException +from SpiffWorkflow.specs.base import TaskSpec # type: ignore +from SpiffWorkflow.task import Task # type: ignore + +from spiffworkflow_backend.services.authentication_service import NotAuthorizedError +from spiffworkflow_backend.services.authentication_service import TokenInvalidError +from spiffworkflow_backend.services.authentication_service import TokenNotProvidedError +from spiffworkflow_backend.services.authentication_service import UserNotLoggedInError + + +api_error_blueprint = Blueprint("api_error_blueprint", __name__) + + +@dataclass +class ApiError(Exception): + """ApiError Class to help handle exceptions.""" + + error_code: str + message: str + error_line: str = "" + error_type: str = "" + file_name: str = "" + line_number: int = 0 + offset: int = 0 + sentry_link: str | None = None + status_code: int = 400 + tag: str = "" + task_data: dict | str | None = field(default_factory=dict) + task_id: str = "" + task_name: str = "" + task_trace: list | None = field(default_factory=list) + + def __str__(self) -> str: + """Instructions to print instance as a string.""" + msg = "ApiError: % s. " % self.message + if self.task_name: + msg += f"Error in task '{self.task_name}' ({self.task_id}). " + if self.line_number: + msg += "Error is on line %i. " % self.line_number + if self.file_name: + msg += "In file %s. " % self.file_name + return msg + + @classmethod + def from_task( + cls, + error_code: str, + message: str, + task: Task, + status_code: int = 400, + line_number: int = 0, + offset: int = 0, + error_type: str = "", + error_line: str = "", + task_trace: list | None = None, + ) -> ApiError: + """Constructs an API Error with details pulled from the current task.""" + instance = cls(error_code, message, status_code=status_code) + instance.task_id = task.task_spec.name or "" + instance.task_name = task.task_spec.description or "" + instance.file_name = task.workflow.spec.file or "" + instance.line_number = line_number + instance.offset = offset + instance.error_type = error_type + instance.error_line = error_line + if task_trace: + instance.task_trace = task_trace + else: + instance.task_trace = WorkflowTaskException.get_task_trace(task) + + # spiffworkflow is doing something weird where task ends up referenced in the data in some cases. + if "task" in task.data: + task.data.pop("task") + + # Assure that there is nothing in the json data that can't be serialized. + instance.task_data = ApiError.remove_unserializeable_from_dict(task.data) + + return instance + + @staticmethod + def remove_unserializeable_from_dict(my_dict: dict) -> dict: + """Removes unserializeable from dict.""" + keys_to_delete = [] + for key, value in my_dict.items(): + if not ApiError.is_jsonable(value): + keys_to_delete.append(key) + for key in keys_to_delete: + del my_dict[key] + return my_dict + + @staticmethod + def is_jsonable(x: Any) -> bool: + """Attempts a json.dump on given input and returns false if it cannot.""" + try: + json.dumps(x) + return True + except (TypeError, OverflowError, ValueError): + return False + + @classmethod + def from_task_spec( + cls, + code: str, + message: str, + task_spec: TaskSpec, + status_code: int = 400, + ) -> ApiError: + """Constructs an API Error with details pulled from the current task.""" + instance = cls(code, message, status_code=status_code) + instance.task_id = task_spec.name or "" + instance.task_name = task_spec.description or "" + if task_spec._wf_spec: + instance.file_name = task_spec._wf_spec.file + return instance + + @classmethod + def from_workflow_exception( + cls, + error_code: str, + message: str, + exp: SpiffWorkflowException, + ) -> ApiError: + """Deals with workflow exceptions. + + We catch a lot of workflow exception errors, + so consolidating the error_code, and doing the best things + we can with the data we have. + """ + if isinstance(exp, WorkflowTaskException): + # Note that WorkflowDataExceptions are also WorkflowTaskExceptions + return ApiError.from_task( + error_code, + message, + exp.task, + line_number=exp.line_number, + offset=exp.offset, + error_type=exp.error_type, + error_line=exp.error_line, + task_trace=exp.task_trace, + ) + elif isinstance(exp, WorkflowException): + return ApiError.from_task_spec(error_code, message, exp.task_spec) + else: + return ApiError("workflow_error", str(exp)) + + +def set_user_sentry_context() -> None: + """Set_user_sentry_context.""" + try: + username = g.user.username + except Exception: + username = "Unknown" + # This is for sentry logging into Slack + sentry_sdk.set_context("User", {"user": username}) + set_tag("username", username) + + +def should_notify_sentry(exception: Exception) -> bool: + """Determine if we should notify sentry. + + We want to capture_exception to log the exception to sentry, but we don't want to log: + 1. ApiErrors that are just invalid tokens + 2. NotAuthorizedError. we usually call check-permissions before calling an API to + make sure we'll have access, but there are some cases + where it's more convenient to just make the call from the frontend and handle the 403 appropriately. + """ + if isinstance(exception, ApiError): + if exception.error_code == "invalid_token": + return False + if isinstance(exception, NotAuthorizedError): + return False + return True + + +@api_error_blueprint.app_errorhandler(Exception) # type: ignore +def handle_exception(exception: Exception) -> flask.wrappers.Response: + """Handles unexpected exceptions.""" + set_user_sentry_context() + + sentry_link = None + if should_notify_sentry(exception): + id = capture_exception(exception) + + if isinstance(exception, ApiError): + current_app.logger.info( + f"Sending ApiError exception to sentry: {exception} with error code" + f" {exception.error_code}" + ) + + organization_slug = current_app.config.get( + "SPIFFWORKFLOW_BACKEND_SENTRY_ORGANIZATION_SLUG" + ) + project_slug = current_app.config.get( + "SPIFFWORKFLOW_BACKEND_SENTRY_PROJECT_SLUG" + ) + if organization_slug and project_slug: + sentry_link = ( + f"https://sentry.io/{organization_slug}/{project_slug}/events/{id}" + ) + + # !!!NOTE!!!: do this after sentry stuff since calling logger.exception + # seems to break the sentry sdk context where we no longer get back + # an event id or send out tags like username + current_app.logger.exception(exception) + else: + current_app.logger.warning( + f"Received exception: {exception}. Since we do not want this particular" + " exception in sentry, we cannot use logger.exception or logger.error, so" + " there will be no backtrace. see api_error.py" + ) + + error_code = "internal_server_error" + status_code = 500 + if ( + isinstance(exception, NotAuthorizedError) + or isinstance(exception, TokenNotProvidedError) + or isinstance(exception, TokenInvalidError) + ): + error_code = "not_authorized" + status_code = 403 + if isinstance(exception, UserNotLoggedInError): + error_code = "not_authenticated" + status_code = 401 + + # set api_exception like this to avoid confusing mypy + # about what type the object is + api_exception = None + if isinstance(exception, ApiError): + api_exception = exception + elif isinstance(exception, SpiffWorkflowException): + api_exception = ApiError.from_workflow_exception( + "unexpected_workflow_exception", "Unexpected Workflow Error", exception + ) + else: + api_exception = ApiError( + error_code=error_code, + message=f"{exception.__class__.__name__}", + sentry_link=sentry_link, + status_code=status_code, + ) + + return make_response(jsonify(api_exception), api_exception.status_code) diff --git a/src/spiffworkflow_backend/helpers/db_helper.py b/src/spiffworkflow_backend/helpers/db_helper.py index 45cd38f7a..57108b6cd 100644 --- a/src/spiffworkflow_backend/helpers/db_helper.py +++ b/src/spiffworkflow_backend/helpers/db_helper.py @@ -2,7 +2,8 @@ import time import sqlalchemy -from flask_bpmn.models.db import db + +from spiffworkflow_backend.models.db import db def try_to_connect(start_time: float) -> None: diff --git a/src/spiffworkflow_backend/load_database_models.py b/src/spiffworkflow_backend/load_database_models.py index bc79a8e39..2ebd11347 100644 --- a/src/spiffworkflow_backend/load_database_models.py +++ b/src/spiffworkflow_backend/load_database_models.py @@ -8,7 +8,7 @@ avoid circular imports """ -from flask_bpmn.models.db import add_listeners +from spiffworkflow_backend.models.db import add_listeners # must load these before UserModel and GroupModel for relationships from spiffworkflow_backend.models.user_group_assignment import ( diff --git a/src/spiffworkflow_backend/models/db.py b/src/spiffworkflow_backend/models/db.py new file mode 100644 index 000000000..5028ad1d5 --- /dev/null +++ b/src/spiffworkflow_backend/models/db.py @@ -0,0 +1,85 @@ +"""Db.""" +from __future__ import annotations + +import enum +import time +from typing import Any + +from flask_migrate import Migrate # type: ignore +from flask_sqlalchemy import SQLAlchemy +from sqlalchemy import event +from sqlalchemy.engine.base import Connection +from sqlalchemy.orm.mapper import Mapper + +db = SQLAlchemy() +migrate = Migrate() + + +class SpiffworkflowBaseDBModel(db.Model): # type: ignore + """SpiffworkflowBaseDBModel.""" + + __abstract__ = True + + @classmethod + def _all_subclasses(cls) -> list[type[SpiffworkflowBaseDBModel]]: + """Get all subclasses of cls, descending. + + So, if A is a subclass of B is a subclass of cls, this + will include A and B. + (Does not include cls) + """ + children = cls.__subclasses__() + result = [] + while children: + next = children.pop() + subclasses = next.__subclasses__() + result.append(next) + # check subclasses of subclasses SpiffworkflowBaseDBModel. i guess we only go down to grandchildren, which seems cool. + for subclass in subclasses: + children.append(subclass) + return result + + def validate_enum_field( + self, key: str, value: Any, enum_variable: enum.EnumMeta + ) -> Any: + """Validate_enum_field.""" + try: + m_type = getattr(enum_variable, value, None) + except Exception as e: + raise ValueError( + f"{self.__class__.__name__}: invalid {key}: {value}" + ) from e + + if m_type is None: + raise ValueError(f"{self.__class__.__name__}: invalid {key}: {value}") + + return m_type.value + + +def update_created_modified_on_create_listener( + mapper: Mapper, _connection: Connection, target: SpiffworkflowBaseDBModel +) -> None: + """Event listener that runs before a record is updated, and sets the create/modified field accordingly.""" + if "created_at_in_seconds" in mapper.columns.keys(): + target.created_at_in_seconds = round(time.time()) + if "updated_at_in_seconds" in mapper.columns.keys(): + target.updated_at_in_seconds = round(time.time()) + + +def update_modified_on_update_listener( + mapper: Mapper, _connection: Connection, target: SpiffworkflowBaseDBModel +) -> None: + """Event listener that runs before a record is updated, and sets the modified field accordingly.""" + if "updated_at_in_seconds" in mapper.columns.keys(): + if db.session.is_modified(target, include_collections=False): + target.updated_at_in_seconds = round(time.time()) + + +def add_listeners() -> None: + """Adds the listeners to all subclasses. + + This should be called after importing all subclasses + """ + for cls in SpiffworkflowBaseDBModel._all_subclasses(): + event.listen(cls, "before_insert", update_created_modified_on_create_listener) # type: ignore + event.listen(cls, "before_update", update_modified_on_update_listener) # type: ignore diff --git a/src/spiffworkflow_backend/models/group.py b/src/spiffworkflow_backend/models/group.py index 980fc9302..f1017df96 100644 --- a/src/spiffworkflow_backend/models/group.py +++ b/src/spiffworkflow_backend/models/group.py @@ -3,10 +3,11 @@ from __future__ import annotations from typing import TYPE_CHECKING -from flask_bpmn.models.db import db -from flask_bpmn.models.group import FlaskBpmnGroupModel from sqlalchemy.orm import relationship +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel + if TYPE_CHECKING: from spiffworkflow_backend.models.user_group_assignment import ( # noqa: F401 UserGroupAssignmentModel, @@ -18,12 +19,14 @@ class GroupNotFoundError(Exception): """GroupNotFoundError.""" -class GroupModel(FlaskBpmnGroupModel): +class GroupModel(SpiffworkflowBaseDBModel): """GroupModel.""" __tablename__ = "group" __table_args__ = {"extend_existing": True} + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(255)) identifier = db.Column(db.String(255)) user_group_assignments = relationship("UserGroupAssignmentModel", cascade="delete") diff --git a/src/spiffworkflow_backend/models/human_task.py b/src/spiffworkflow_backend/models/human_task.py index f74da5cca..3317f7732 100644 --- a/src/spiffworkflow_backend/models/human_task.py +++ b/src/spiffworkflow_backend/models/human_task.py @@ -4,11 +4,11 @@ from __future__ import annotations from dataclasses import dataclass from typing import TYPE_CHECKING -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy import ForeignKey from sqlalchemy.orm import relationship +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.group import GroupModel from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.task import Task @@ -26,9 +26,6 @@ class HumanTaskModel(SpiffworkflowBaseDBModel): """HumanTaskModel.""" __tablename__ = "human_task" - __table_args__ = ( - db.UniqueConstraint("task_id", "process_instance_id", name="human_task_unique"), - ) id: int = db.Column(db.Integer, primary_key=True) process_instance_id: int = db.Column( diff --git a/src/spiffworkflow_backend/models/human_task_user.py b/src/spiffworkflow_backend/models/human_task_user.py index 31823af82..1e4831778 100644 --- a/src/spiffworkflow_backend/models/human_task_user.py +++ b/src/spiffworkflow_backend/models/human_task_user.py @@ -3,10 +3,11 @@ from __future__ import annotations from dataclasses import dataclass -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy import ForeignKey +from sqlalchemy.orm import relationship +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.human_task import HumanTaskModel from spiffworkflow_backend.models.user import UserModel @@ -30,3 +31,5 @@ class HumanTaskUserModel(SpiffworkflowBaseDBModel): ForeignKey(HumanTaskModel.id), nullable=False, index=True # type: ignore ) user_id = db.Column(ForeignKey(UserModel.id), nullable=False, index=True) # type: ignore + + human_task = relationship(HumanTaskModel) diff --git a/src/spiffworkflow_backend/models/message_correlation.py b/src/spiffworkflow_backend/models/message_correlation.py index 08bc1cb12..e913938f5 100644 --- a/src/spiffworkflow_backend/models/message_correlation.py +++ b/src/spiffworkflow_backend/models/message_correlation.py @@ -2,11 +2,11 @@ from dataclasses import dataclass from typing import TYPE_CHECKING -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy import ForeignKey from sqlalchemy.orm import relationship +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.message_correlation_property import ( MessageCorrelationPropertyModel, ) diff --git a/src/spiffworkflow_backend/models/message_correlation_message_instance.py b/src/spiffworkflow_backend/models/message_correlation_message_instance.py index 320dfba3e..58ded838b 100644 --- a/src/spiffworkflow_backend/models/message_correlation_message_instance.py +++ b/src/spiffworkflow_backend/models/message_correlation_message_instance.py @@ -1,10 +1,10 @@ """Message_correlation_message_instance.""" from dataclasses import dataclass -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy import ForeignKey +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.message_correlation import MessageCorrelationModel from spiffworkflow_backend.models.message_instance import MessageInstanceModel diff --git a/src/spiffworkflow_backend/models/message_correlation_property.py b/src/spiffworkflow_backend/models/message_correlation_property.py index b84b7140c..1e09dc0c4 100644 --- a/src/spiffworkflow_backend/models/message_correlation_property.py +++ b/src/spiffworkflow_backend/models/message_correlation_property.py @@ -1,8 +1,8 @@ """Message_correlation_property.""" -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy import ForeignKey +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.message_model import MessageModel diff --git a/src/spiffworkflow_backend/models/message_instance.py b/src/spiffworkflow_backend/models/message_instance.py index b0cc2aa34..c9ea515e6 100644 --- a/src/spiffworkflow_backend/models/message_instance.py +++ b/src/spiffworkflow_backend/models/message_instance.py @@ -5,14 +5,14 @@ from typing import Any from typing import Optional from typing import TYPE_CHECKING -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy import ForeignKey from sqlalchemy.event import listens_for from sqlalchemy.orm import relationship from sqlalchemy.orm import Session from sqlalchemy.orm import validates +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.message_model import MessageModel from spiffworkflow_backend.models.process_instance import ProcessInstanceModel diff --git a/src/spiffworkflow_backend/models/message_model.py b/src/spiffworkflow_backend/models/message_model.py index 601b6d405..8ebd15c56 100644 --- a/src/spiffworkflow_backend/models/message_model.py +++ b/src/spiffworkflow_backend/models/message_model.py @@ -1,6 +1,6 @@ """Message_model.""" -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel class MessageModel(SpiffworkflowBaseDBModel): diff --git a/src/spiffworkflow_backend/models/message_triggerable_process_model.py b/src/spiffworkflow_backend/models/message_triggerable_process_model.py index cc8834654..edf648218 100644 --- a/src/spiffworkflow_backend/models/message_triggerable_process_model.py +++ b/src/spiffworkflow_backend/models/message_triggerable_process_model.py @@ -1,8 +1,8 @@ """Message_correlation_property.""" -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy import ForeignKey +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.message_model import MessageModel diff --git a/src/spiffworkflow_backend/models/permission_assignment.py b/src/spiffworkflow_backend/models/permission_assignment.py index 04dfb5fac..a9db96cfa 100644 --- a/src/spiffworkflow_backend/models/permission_assignment.py +++ b/src/spiffworkflow_backend/models/permission_assignment.py @@ -2,11 +2,11 @@ import enum from typing import Any -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy import ForeignKey from sqlalchemy.orm import validates +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.permission_target import PermissionTargetModel from spiffworkflow_backend.models.principal import PrincipalModel diff --git a/src/spiffworkflow_backend/models/permission_target.py b/src/spiffworkflow_backend/models/permission_target.py index 53334baf0..773833a39 100644 --- a/src/spiffworkflow_backend/models/permission_target.py +++ b/src/spiffworkflow_backend/models/permission_target.py @@ -3,10 +3,11 @@ import re from dataclasses import dataclass from typing import Optional -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy.orm import validates +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel + class InvalidPermissionTargetUriError(Exception): """InvalidPermissionTargetUriError.""" diff --git a/src/spiffworkflow_backend/models/principal.py b/src/spiffworkflow_backend/models/principal.py index ac8ee6a4e..6e46def5b 100644 --- a/src/spiffworkflow_backend/models/principal.py +++ b/src/spiffworkflow_backend/models/principal.py @@ -1,12 +1,12 @@ """Principal.""" from dataclasses import dataclass -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy import ForeignKey from sqlalchemy.orm import relationship from sqlalchemy.schema import CheckConstraint +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.group import GroupModel from spiffworkflow_backend.models.user import UserModel diff --git a/src/spiffworkflow_backend/models/process_instance.py b/src/spiffworkflow_backend/models/process_instance.py index 42a903648..95930958b 100644 --- a/src/spiffworkflow_backend/models/process_instance.py +++ b/src/spiffworkflow_backend/models/process_instance.py @@ -5,8 +5,6 @@ from typing import Any from typing import cast import marshmallow -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from marshmallow import INCLUDE from marshmallow import Schema from marshmallow_enum import EnumField # type: ignore @@ -17,6 +15,8 @@ from sqlalchemy.orm import relationship from sqlalchemy.orm import validates from spiffworkflow_backend.helpers.spiff_enum import SpiffEnum +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.task import Task from spiffworkflow_backend.models.task import TaskSchema from spiffworkflow_backend.models.user import UserModel @@ -75,6 +75,10 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel): ) # type: ignore message_instances = relationship("MessageInstanceModel", cascade="delete") # type: ignore message_correlations = relationship("MessageCorrelationModel", cascade="delete") # type: ignore + process_metadata = relationship( + "ProcessInstanceMetadataModel", + cascade="delete", + ) # type: ignore bpmn_json: str | None = deferred(db.Column(db.JSON)) # type: ignore start_in_seconds: int | None = db.Column(db.Integer) @@ -83,11 +87,16 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel): created_at_in_seconds: int = db.Column(db.Integer) status: str = db.Column(db.String(50)) - bpmn_xml_file_contents: str | None = None bpmn_version_control_type: str = db.Column(db.String(50)) bpmn_version_control_identifier: str = db.Column(db.String(255)) spiff_step: int = db.Column(db.Integer) + locked_by: str | None = db.Column(db.String(80)) + locked_at_in_seconds: int | None = db.Column(db.Integer) + + bpmn_xml_file_contents: str | None = None + process_model_with_diagram_identifier: str | None = None + @property def serialized(self) -> dict[str, Any]: """Return object data in serializeable format.""" @@ -108,6 +117,14 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel): "process_initiator_username": self.process_initiator.username, } + def serialized_with_metadata(self) -> dict[str, Any]: + process_instance_attributes = self.serialized + process_instance_attributes["process_metadata"] = self.process_metadata + process_instance_attributes["process_model_with_diagram_identifier"] = ( + self.process_model_with_diagram_identifier + ) + return process_instance_attributes + @property def serialized_flat(self) -> dict: """Return object in serializeable format with data merged together with top-level attributes. diff --git a/src/spiffworkflow_backend/models/process_instance_metadata.py b/src/spiffworkflow_backend/models/process_instance_metadata.py index f2e4c2221..920e13a2c 100644 --- a/src/spiffworkflow_backend/models/process_instance_metadata.py +++ b/src/spiffworkflow_backend/models/process_instance_metadata.py @@ -1,10 +1,10 @@ """Process_instance_metadata.""" from dataclasses import dataclass -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy import ForeignKey +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.process_instance import ProcessInstanceModel diff --git a/src/spiffworkflow_backend/models/process_instance_report.py b/src/spiffworkflow_backend/models/process_instance_report.py index b1288b3f1..a8787da62 100644 --- a/src/spiffworkflow_backend/models/process_instance_report.py +++ b/src/spiffworkflow_backend/models/process_instance_report.py @@ -7,8 +7,6 @@ from typing import cast from typing import Optional from typing import TypedDict -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy import ForeignKey from sqlalchemy.orm import deferred from sqlalchemy.orm import relationship @@ -16,6 +14,8 @@ from sqlalchemy.orm import relationship from spiffworkflow_backend.exceptions.process_entity_not_found_error import ( ProcessEntityNotFoundError, ) +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.user import UserModel from spiffworkflow_backend.services.process_instance_processor import ( diff --git a/src/spiffworkflow_backend/models/refresh_token.py b/src/spiffworkflow_backend/models/refresh_token.py index 2e96b7f05..d7bf0fe1e 100644 --- a/src/spiffworkflow_backend/models/refresh_token.py +++ b/src/spiffworkflow_backend/models/refresh_token.py @@ -1,10 +1,11 @@ """Refresh_token.""" from dataclasses import dataclass -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy import ForeignKey +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel + # from sqlalchemy.orm import relationship # from spiffworkflow_backend.models.user import UserModel diff --git a/src/spiffworkflow_backend/models/secret_model.py b/src/spiffworkflow_backend/models/secret_model.py index 91a4f23bb..026831eda 100644 --- a/src/spiffworkflow_backend/models/secret_model.py +++ b/src/spiffworkflow_backend/models/secret_model.py @@ -1,11 +1,11 @@ """Secret_model.""" from dataclasses import dataclass -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from marshmallow import Schema from sqlalchemy import ForeignKey +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.user import UserModel diff --git a/src/spiffworkflow_backend/models/spec_reference.py b/src/spiffworkflow_backend/models/spec_reference.py index 50b73fbae..090cf70a4 100644 --- a/src/spiffworkflow_backend/models/spec_reference.py +++ b/src/spiffworkflow_backend/models/spec_reference.py @@ -1,12 +1,13 @@ """Message_model.""" from dataclasses import dataclass -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from flask_marshmallow import Schema # type: ignore from marshmallow import INCLUDE from sqlalchemy import UniqueConstraint +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel + class SpecReferenceNotFoundError(Exception): """SpecReferenceNotFoundError.""" diff --git a/src/spiffworkflow_backend/models/spiff_logging.py b/src/spiffworkflow_backend/models/spiff_logging.py index 532a6c09c..71e1bbfbd 100644 --- a/src/spiffworkflow_backend/models/spiff_logging.py +++ b/src/spiffworkflow_backend/models/spiff_logging.py @@ -2,8 +2,8 @@ from dataclasses import dataclass from typing import Optional -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel @dataclass diff --git a/src/spiffworkflow_backend/models/spiff_step_details.py b/src/spiffworkflow_backend/models/spiff_step_details.py index 11c3aeada..9fd1b2961 100644 --- a/src/spiffworkflow_backend/models/spiff_step_details.py +++ b/src/spiffworkflow_backend/models/spiff_step_details.py @@ -1,11 +1,13 @@ """Spiff_step_details.""" from dataclasses import dataclass +from typing import Union -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy import ForeignKey +from sqlalchemy import UniqueConstraint from sqlalchemy.orm import deferred +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.process_instance import ProcessInstanceModel @@ -14,17 +16,25 @@ class SpiffStepDetailsModel(SpiffworkflowBaseDBModel): """SpiffStepDetailsModel.""" __tablename__ = "spiff_step_details" + __table_args__ = ( + UniqueConstraint( + "process_instance_id", "spiff_step", name="process_instance_id_spiff_step" + ), + ) + id: int = db.Column(db.Integer, primary_key=True) process_instance_id: int = db.Column( ForeignKey(ProcessInstanceModel.id), nullable=False # type: ignore ) - # human_task_id: int = db.Column( - # ForeignKey(HumanTaskModel.id) # type: ignore - # ) spiff_step: int = db.Column(db.Integer, nullable=False) task_json: dict = deferred(db.Column(db.JSON, nullable=False)) # type: ignore - timestamp: float = db.Column(db.DECIMAL(17, 6), nullable=False) - # completed_by_user_id: int = db.Column(db.Integer, nullable=True) - # lane_assignment_id: Optional[int] = db.Column( - # ForeignKey(GroupModel.id), nullable=True - # ) + task_id: str = db.Column(db.String(50), nullable=False) + task_state: str = db.Column(db.String(50), nullable=False) + bpmn_task_identifier: str = db.Column(db.String(255), nullable=False) + + start_in_seconds: float = db.Column(db.DECIMAL(17, 6), nullable=False) + + # to fix mypy in 3.9 - not sure why syntax like: + # float | None + # works in other dataclass db models + end_in_seconds: Union[float, None] = db.Column(db.DECIMAL(17, 6)) diff --git a/src/spiffworkflow_backend/models/task.py b/src/spiffworkflow_backend/models/task.py index 5c924196a..413be5e5a 100644 --- a/src/spiffworkflow_backend/models/task.py +++ b/src/spiffworkflow_backend/models/task.py @@ -7,6 +7,7 @@ from typing import Union import marshmallow from marshmallow import Schema from marshmallow_enum import EnumField # type: ignore +from SpiffWorkflow.task import TaskStateNames # type: ignore class MultiInstanceType(enum.Enum): @@ -115,12 +116,13 @@ class Task: process_model_display_name: Union[str, None] = None, process_group_identifier: Union[str, None] = None, process_model_identifier: Union[str, None] = None, - form_schema: Union[str, None] = None, - form_ui_schema: Union[str, None] = None, + form_schema: Union[dict, None] = None, + form_ui_schema: Union[dict, None] = None, parent: Optional[str] = None, event_definition: Union[dict[str, Any], None] = None, call_activity_process_identifier: Optional[str] = None, calling_subprocess_task_id: Optional[str] = None, + task_spiff_step: Optional[int] = None, ): """__init__.""" self.id = id @@ -135,6 +137,7 @@ class Task: self.event_definition = event_definition self.call_activity_process_identifier = call_activity_process_identifier self.calling_subprocess_task_id = calling_subprocess_task_id + self.task_spiff_step = task_spiff_step self.data = data if self.data is None: @@ -196,6 +199,7 @@ class Task: "event_definition": self.event_definition, "call_activity_process_identifier": self.call_activity_process_identifier, "calling_subprocess_task_id": self.calling_subprocess_task_id, + "task_spiff_step": self.task_spiff_step, } @classmethod @@ -212,6 +216,12 @@ class Task: value for name, value in vars(cls).items() if name.startswith("FIELD_TYPE") ] + @classmethod + def task_state_name_to_int(cls, task_state_name: str) -> int: + task_state_integers = {v: k for k, v in TaskStateNames.items()} + task_state_int: int = task_state_integers[task_state_name] + return task_state_int + class OptionSchema(Schema): """OptionSchema.""" diff --git a/src/spiffworkflow_backend/models/user.py b/src/spiffworkflow_backend/models/user.py index c4838aafa..464bdc8b2 100644 --- a/src/spiffworkflow_backend/models/user.py +++ b/src/spiffworkflow_backend/models/user.py @@ -6,11 +6,11 @@ from dataclasses import dataclass import jwt import marshmallow from flask import current_app -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from marshmallow import Schema from sqlalchemy.orm import relationship +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.group import GroupModel @@ -34,6 +34,9 @@ class UserModel(SpiffworkflowBaseDBModel): service_id = db.Column(db.String(255), nullable=False, unique=False) display_name = db.Column(db.String(255)) email = db.Column(db.String(255)) + tenant_specific_field_1: str | None = db.Column(db.String(255)) + tenant_specific_field_2: str | None = db.Column(db.String(255)) + tenant_specific_field_3: str | None = db.Column(db.String(255)) updated_at_in_seconds: int = db.Column(db.Integer) created_at_in_seconds: int = db.Column(db.Integer) diff --git a/src/spiffworkflow_backend/models/user_group_assignment.py b/src/spiffworkflow_backend/models/user_group_assignment.py index 9c1567fb7..acd6c30b2 100644 --- a/src/spiffworkflow_backend/models/user_group_assignment.py +++ b/src/spiffworkflow_backend/models/user_group_assignment.py @@ -1,9 +1,9 @@ """UserGroupAssignment.""" -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy import ForeignKey from sqlalchemy.orm import relationship +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.group import GroupModel from spiffworkflow_backend.models.user import UserModel diff --git a/src/spiffworkflow_backend/models/user_group_assignment_waiting.py b/src/spiffworkflow_backend/models/user_group_assignment_waiting.py index ac2747c85..7db1676f9 100644 --- a/src/spiffworkflow_backend/models/user_group_assignment_waiting.py +++ b/src/spiffworkflow_backend/models/user_group_assignment_waiting.py @@ -1,9 +1,9 @@ """UserGroupAssignment.""" -from flask_bpmn.models.db import db -from flask_bpmn.models.db import SpiffworkflowBaseDBModel from sqlalchemy import ForeignKey from sqlalchemy.orm import relationship +from spiffworkflow_backend.models.db import db +from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.group import GroupModel diff --git a/src/spiffworkflow_backend/routes/admin_blueprint/__init__.py b/src/spiffworkflow_backend/routes/admin_blueprint/__init__.py deleted file mode 100644 index f520b09de..000000000 --- a/src/spiffworkflow_backend/routes/admin_blueprint/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""__init__.""" diff --git a/src/spiffworkflow_backend/routes/admin_blueprint/admin_blueprint.py b/src/spiffworkflow_backend/routes/admin_blueprint/admin_blueprint.py deleted file mode 100644 index 5cb0ae89b..000000000 --- a/src/spiffworkflow_backend/routes/admin_blueprint/admin_blueprint.py +++ /dev/null @@ -1,187 +0,0 @@ -"""APIs for dealing with process groups, process models, and process instances.""" -from typing import Union - -from flask import Blueprint -from flask import flash -from flask import redirect -from flask import render_template -from flask import request -from flask import url_for -from werkzeug.wrappers import Response - -from spiffworkflow_backend.services.process_instance_processor import ( - ProcessInstanceProcessor, -) -from spiffworkflow_backend.services.process_instance_service import ( - ProcessInstanceService, -) -from spiffworkflow_backend.services.process_model_service import ProcessModelService -from spiffworkflow_backend.services.spec_file_service import SpecFileService -from spiffworkflow_backend.services.user_service import UserService - -admin_blueprint = Blueprint( - "admin", __name__, template_folder="templates", static_folder="static" -) - -ALLOWED_BPMN_EXTENSIONS = {"bpmn", "dmn"} - - -@admin_blueprint.route("/process-groups", methods=["GET"]) -def process_group_list() -> str: - """Process_group_list.""" - process_groups = ProcessModelService.get_process_groups() - return render_template("process_group_list.html", process_groups=process_groups) - - -@admin_blueprint.route("/process-groups/", methods=["GET"]) -def process_group_show(process_group_id: str) -> str: - """Show_process_group.""" - process_group = ProcessModelService.get_process_group(process_group_id) - return render_template("process_group_show.html", process_group=process_group) - - -@admin_blueprint.route("/process-models/", methods=["GET"]) -def process_model_show(process_model_id: str) -> Union[str, Response]: - """Show_process_model.""" - process_model = ProcessModelService.get_process_model(process_model_id) - files = SpecFileService.get_files(process_model, extension_filter="bpmn") - current_file_name = process_model.primary_file_name - if current_file_name is None: - flash("No primary_file_name", "error") - return redirect(url_for("admin.process_group_list")) - bpmn_xml = SpecFileService.get_data(process_model, current_file_name) - return render_template( - "process_model_show.html", - process_model=process_model, - bpmn_xml=bpmn_xml, - files=files, - current_file_name=current_file_name, - ) - - -@admin_blueprint.route( - "/process-models//", methods=["GET"] -) -def process_model_show_file(process_model_id: str, file_name: str) -> str: - """Process_model_show_file.""" - process_model = ProcessModelService.get_process_model(process_model_id) - bpmn_xml = SpecFileService.get_data(process_model, file_name) - files = SpecFileService.get_files(process_model, extension_filter="bpmn") - return render_template( - "process_model_show.html", - process_model=process_model, - bpmn_xml=bpmn_xml, - files=files, - current_file_name=file_name, - ) - - -@admin_blueprint.route( - "/process-models//upload-file", methods=["POST"] -) -def process_model_upload_file(process_model_id: str) -> Response: - """Process_model_upload_file.""" - process_model = ProcessModelService.get_process_model(process_model_id) - - if "file" not in request.files: - flash("No file part", "error") - request_file = request.files["file"] - # If the user does not select a file, the browser submits an - # empty file without a filename. - if request_file.filename == "" or request_file.filename is None: - flash("No selected file", "error") - else: - if request_file and _allowed_file(request_file.filename): - if request_file.filename is not None: - SpecFileService.add_file( - process_model, request_file.filename, request_file.stream.read() - ) - ProcessModelService.save_process_model(process_model) - - return redirect( - url_for("admin.process_model_show", process_model_id=process_model.id) - ) - - -@admin_blueprint.route( - "/process_models//edit/", methods=["GET"] -) -def process_model_edit(process_model_id: str, file_name: str) -> str: - """Edit_bpmn.""" - process_model = ProcessModelService.get_process_model(process_model_id) - bpmn_xml = SpecFileService.get_data(process_model, file_name) - - return render_template( - "process_model_edit.html", - bpmn_xml=bpmn_xml.decode("utf-8"), - process_model=process_model, - file_name=file_name, - ) - - -@admin_blueprint.route( - "/process-models//save/", methods=["POST"] -) -def process_model_save(process_model_id: str, file_name: str) -> Union[str, Response]: - """Process_model_save.""" - process_model = ProcessModelService.get_process_model(process_model_id) - SpecFileService.update_file(process_model, file_name, request.get_data()) - if process_model.primary_file_name is None: - flash("No primary_file_name", "error") - return redirect(url_for("admin.process_group_list")) - bpmn_xml = SpecFileService.get_data(process_model, process_model.primary_file_name) - return render_template( - "process_model_edit.html", - bpmn_xml=bpmn_xml.decode("utf-8"), - process_model=process_model, - file_name=file_name, - ) - - -@admin_blueprint.route("/process-models//run", methods=["GET"]) -def process_model_run(process_model_id: str) -> Union[str, Response]: - """Process_model_run.""" - user = UserService.create_user("Mr. Test", "internal", "Mr. Test") - process_instance = ( - ProcessInstanceService.create_process_instance_from_process_model_identifier( - process_model_id, user - ) - ) - processor = ProcessInstanceProcessor(process_instance) - processor.do_engine_steps() - result = processor.get_data() - - process_model = ProcessModelService.get_process_model(process_model_id) - files = SpecFileService.get_files(process_model, extension_filter="bpmn") - current_file_name = process_model.primary_file_name - if current_file_name is None: - flash("No primary_file_name", "error") - return redirect(url_for("admin.process_group_list")) - bpmn_xml = SpecFileService.get_data(process_model, current_file_name) - - return render_template( - "process_model_show.html", - process_model=process_model, - bpmn_xml=bpmn_xml, - result=result, - files=files, - current_file_name=current_file_name, - ) - - -# def _find_or_create_user(username: str = "test_user1") -> Any: -# """Find_or_create_user.""" -# user = UserModel.query.filter_by(username=username).first() -# if user is None: -# user = UserModel(username=username) -# db.session.add(user) -# db.session.commit() -# return user - - -def _allowed_file(filename: str) -> bool: - """_allowed_file.""" - return ( - "." in filename - and filename.rsplit(".", 1)[1].lower() in ALLOWED_BPMN_EXTENSIONS - ) diff --git a/src/spiffworkflow_backend/routes/admin_blueprint/static/app.js b/src/spiffworkflow_backend/routes/admin_blueprint/static/app.js deleted file mode 100644 index 5fb392dcd..000000000 --- a/src/spiffworkflow_backend/routes/admin_blueprint/static/app.js +++ /dev/null @@ -1,26 +0,0 @@ -import BpmnViewer from "bpmn-js"; - -var viewer = new BpmnViewer({ - container: "#canvas", -}); - -viewer - .importXML(pizzaDiagram) - .then(function (result) { - const { warnings } = result; - - console.log("success !", warnings); - - viewer.get("canvas").zoom("fit-viewport"); - }) - .catch(function (err) { - const { warnings, message } = err; - - console.log("something went wrong:", warnings, message); - }); - -export function sayHello() { - console.log("hello"); -} - -window.foo = "bar"; diff --git a/src/spiffworkflow_backend/routes/admin_blueprint/static/package-lock.json b/src/spiffworkflow_backend/routes/admin_blueprint/static/package-lock.json deleted file mode 100644 index b73679283..000000000 --- a/src/spiffworkflow_backend/routes/admin_blueprint/static/package-lock.json +++ /dev/null @@ -1,3172 +0,0 @@ -{ - "name": "spiffworkflow-backend", - "version": "0.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "spiffworkflow-backend", - "version": "0.0.0", - "license": "ISC", - "dependencies": { - "bpmn-js": "^9.1.0", - "bpmn-js-properties-panel": "^1.1.1" - }, - "devDependencies": { - "webpack-cli": "^4.9.2" - } - }, - "node_modules/@bpmn-io/element-templates-validator": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@bpmn-io/element-templates-validator/-/element-templates-validator-0.8.1.tgz", - "integrity": "sha512-cJMVYXxQAkntBZ2Brr76AI8D8xXWNS9GI8YM0h5kjkTihfYC+7FfN744RM1RVx8zJqTzOMf8nkS37t95Re4wvA==", - "dependencies": { - "@camunda/element-templates-json-schema": "^0.9.1", - "@camunda/zeebe-element-templates-json-schema": "^0.4.1", - "json-source-map": "^0.6.1", - "min-dash": "^3.8.1" - } - }, - "node_modules/@bpmn-io/extract-process-variables": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/@bpmn-io/extract-process-variables/-/extract-process-variables-0.4.5.tgz", - "integrity": "sha512-LtHx5b9xqS8avRLrq/uTlKhWzMeV3bWQKIdDic2bdo5n9roitX13GRb01u2S0hSsKDWEhXQtydFYN2b6G7bqfw==", - "dependencies": { - "min-dash": "^3.8.1" - } - }, - "node_modules/@bpmn-io/properties-panel": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/@bpmn-io/properties-panel/-/properties-panel-0.13.2.tgz", - "integrity": "sha512-S0FUjXApQ8V1tW3TkrmuxXkfiMv6WPdeKkc7DD9tzKTHHnT634GY4pafKPPknxYsLGthUiJghqWbuQahqQjz+g==", - "peer": true, - "dependencies": { - "classnames": "^2.3.1", - "diagram-js": "^8.1.2", - "min-dash": "^3.7.0", - "min-dom": "^3.1.3" - } - }, - "node_modules/@camunda/element-templates-json-schema": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@camunda/element-templates-json-schema/-/element-templates-json-schema-0.9.1.tgz", - "integrity": "sha512-hqAOdwf0EdEDughDAfsOWtQQaKx/7m3srVbrUfVZy2Nh2mUc3hyBbkODO4tkMjTKv6I4bw36cyMchzjIEaz4CA==" - }, - "node_modules/@camunda/zeebe-element-templates-json-schema": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@camunda/zeebe-element-templates-json-schema/-/zeebe-element-templates-json-schema-0.4.1.tgz", - "integrity": "sha512-FAe7auxm+IJiRB0W68VOjBxih6aOJB/0K3nvjO0TtRdyS+a2X1DIDBDtsQO6g+pJDtW6oij0kC1LiBUvm6FmLw==" - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", - "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", - "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", - "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", - "dev": true, - "peer": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", - "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@philippfromme/moddle-helpers": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@philippfromme/moddle-helpers/-/moddle-helpers-0.4.1.tgz", - "integrity": "sha512-6ST9WdafFGh/vxeQP4pwFkcGcqIQJ0mtQSrXwoetTLigCXCcP4UXdXxjcIEwWKoXuexXV/2CgFS0CPENSVcwdg==", - "dependencies": { - "min-dash": "^3.8.1" - } - }, - "node_modules/@types/eslint": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz", - "integrity": "sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA==", - "dev": true, - "peer": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", - "dev": true, - "peer": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", - "dev": true, - "peer": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true, - "peer": true - }, - "node_modules/@types/node": { - "version": "17.0.38", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.38.tgz", - "integrity": "sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dev": true, - "peer": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dev": true, - "peer": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webpack-cli/configtest": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", - "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==", - "dev": true, - "peerDependencies": { - "webpack": "4.x.x || 5.x.x", - "webpack-cli": "4.x.x" - } - }, - "node_modules/@webpack-cli/info": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz", - "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==", - "dev": true, - "dependencies": { - "envinfo": "^7.7.3" - }, - "peerDependencies": { - "webpack-cli": "4.x.x" - } - }, - "node_modules/@webpack-cli/serve": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", - "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==", - "dev": true, - "peerDependencies": { - "webpack-cli": "4.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true, - "peer": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true, - "peer": true - }, - "node_modules/acorn": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", - "dev": true, - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "peer": true, - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peer": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/array-move": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/array-move/-/array-move-3.0.1.tgz", - "integrity": "sha512-H3Of6NIn2nNU1gsVDqDnYKY/LCdWvCMMOWifNGhKcVQgiZ6nOek39aESOvro6zmueP07exSl93YLvkN4fZOkSg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bpmn-js": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/bpmn-js/-/bpmn-js-9.1.0.tgz", - "integrity": "sha512-LFrNVt15hCvTJ7RrdshJeNYyLPAJQKC8sBCXvnFoLuwfuBwNbxkDtaripzrkgCj7X5wyduh+ogZ4KaE5xwsTbA==", - "dependencies": { - "bpmn-moddle": "^7.1.2", - "css.escape": "^1.5.1", - "diagram-js": "^8.3.0", - "diagram-js-direct-editing": "^1.6.3", - "ids": "^1.0.0", - "inherits": "^2.0.4", - "min-dash": "^3.5.2", - "min-dom": "^3.2.0", - "object-refs": "^0.3.0", - "tiny-svg": "^2.2.2" - } - }, - "node_modules/bpmn-js-properties-panel": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/bpmn-js-properties-panel/-/bpmn-js-properties-panel-1.1.1.tgz", - "integrity": "sha512-FIxg3yIeKtYzDFLqI9GzhYBYDh12WtyvHFOSl4bSlDUQJIs31Xe7yobECEZNQ+00XtmtKUK96ikHUti5YydgDQ==", - "dependencies": { - "@bpmn-io/element-templates-validator": "^0.8.1", - "@bpmn-io/extract-process-variables": "^0.4.5", - "@philippfromme/moddle-helpers": "^0.4.1", - "array-move": "^3.0.1", - "classnames": "^2.3.1", - "ids": "^1.0.0", - "min-dash": "^3.8.1", - "min-dom": "^3.1.3", - "preact-markup": "^2.1.1", - "semver-compare": "^1.0.0" - }, - "peerDependencies": { - "@bpmn-io/properties-panel": "0.13.x", - "bpmn-js": "8.x || 9.x", - "camunda-bpmn-js-behaviors": "0.1.x", - "diagram-js": "7.x || 8.x" - } - }, - "node_modules/bpmn-moddle": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/bpmn-moddle/-/bpmn-moddle-7.1.2.tgz", - "integrity": "sha512-Sax4LokRCTqlg26njjULN3ZGtCmwH5gZVUZTRF0jwJk+YpMQhSfSoUECxjNv8OROoLxu8Z+MjdOHIxgvJf7KwA==", - "dependencies": { - "min-dash": "^3.5.2", - "moddle": "^5.0.2", - "moddle-xml": "^9.0.5" - } - }, - "node_modules/browserslist": { - "version": "4.20.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", - "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "peer": true, - "dependencies": { - "caniuse-lite": "^1.0.30001332", - "electron-to-chromium": "^1.4.118", - "escalade": "^3.1.1", - "node-releases": "^2.0.3", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "peer": true - }, - "node_modules/camunda-bpmn-js-behaviors": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/camunda-bpmn-js-behaviors/-/camunda-bpmn-js-behaviors-0.1.0.tgz", - "integrity": "sha512-YJs4kAkRhZ1GyE4VVPTJlZ/GjuDHnSGvzuLTa87HIfpEonVMHsmRrQL0Gr/bkSVcQaA4s6XB0XKV6rz32LHNUA==", - "peer": true, - "dependencies": { - "ids": "^1.0.0", - "min-dash": "^3.7.0" - }, - "peerDependencies": { - "bpmn-js": "9.x", - "camunda-bpmn-moddle": "6.x", - "zeebe-bpmn-moddle": "0.12.x" - } - }, - "node_modules/camunda-bpmn-moddle": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/camunda-bpmn-moddle/-/camunda-bpmn-moddle-6.1.2.tgz", - "integrity": "sha512-DfhOTeq8oN01cB5sLE6Rq34/9xGD15/Y14pEM+YBIjgvV6Rclh+BgIa/2aRMm8An4Kc/itm2tECYiDr8p/FyTQ==", - "peer": true, - "dependencies": { - "min-dash": "^3.8.1" - }, - "peerDependencies": { - "bpmn-js": "^6.x || ^7.x || ^8.x || ^9.x", - "diagram-js": "^5.x || ^6.x || ^7.x || ^8.x" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001344", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz", - "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ], - "peer": true - }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/classnames": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", - "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", - "dev": true - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "peer": true - }, - "node_modules/component-event": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/component-event/-/component-event-0.1.4.tgz", - "integrity": "sha512-GMwOG8MnUHP1l8DZx1ztFO0SJTFnIzZnBDkXAj8RM2ntV2A6ALlDxgbMY1Fvxlg6WPQ+5IM/a6vg4PEYbjg/Rw==" - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=" - }, - "node_modules/diagram-js": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/diagram-js/-/diagram-js-8.5.0.tgz", - "integrity": "sha512-UHA/Zfs7kG22M9wXAifAyPb2OZ4lG4lFi0CZ0GC6/lXmOsSHwHVZ1s/h9UqaIXnzIKW8SnZoP3Rwqel1ZhZLzg==", - "dependencies": { - "css.escape": "^1.5.1", - "didi": "^8.0.0", - "hammerjs": "^2.0.1", - "inherits-browser": "0.0.1", - "min-dash": "^3.5.2", - "min-dom": "^3.2.0", - "object-refs": "^0.3.0", - "path-intersection": "^2.2.1", - "tiny-svg": "^2.2.2" - } - }, - "node_modules/diagram-js-direct-editing": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/diagram-js-direct-editing/-/diagram-js-direct-editing-1.7.0.tgz", - "integrity": "sha512-ZfTLF4hdWr7NSoruwxGvVmu7aVaUjWRXjwgK5dx58LbXAsNjBS3Ap7zjVuGxjWUpCZ/MMwyZ00lpTHPH2P7BFQ==", - "dependencies": { - "min-dash": "^3.5.2", - "min-dom": "^3.1.3" - }, - "peerDependencies": { - "diagram-js": "^0.x || ^1.x || ^2.x || ^3.x || ^4.x || ^5.x || ^6.x || ^7.x || ^8.x" - } - }, - "node_modules/didi": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/didi/-/didi-8.0.0.tgz", - "integrity": "sha512-PwqTBaYzzfJSyxvpXPcTWF6nDdCKx2mFAU5eup1ZSb5wbaAS9a/HiKdtcAUdie/VMLHoFI50jkYZcA+bhUOugw==" - }, - "node_modules/domify": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/domify/-/domify-1.4.1.tgz", - "integrity": "sha512-x18nuiDHMCZGXr4KJSRMf/TWYtiaRo6RX8KN9fEbW54mvbQ6pieUuerC2ahBg+kEp1wycFj8MPUI0WkIOw5E9w==" - }, - "node_modules/electron-to-chromium": { - "version": "1.4.143", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.143.tgz", - "integrity": "sha512-2hIgvu0+pDfXIqmVmV5X6iwMjQ2KxDsWKwM+oI1fABEOy/Dqmll0QJRmIQ3rm+XaoUa/qKrmy5h7LSTFQ6Ldzg==", - "dev": true, - "peer": true - }, - "node_modules/enhanced-resolve": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", - "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", - "dev": true, - "peer": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", - "dev": true, - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", - "dev": true, - "peer": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "peer": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "peer": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "peer": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "peer": true - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", - "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", - "dev": true - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true, - "peer": true - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true, - "peer": true - }, - "node_modules/hammerjs": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", - "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/ids": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ids/-/ids-1.0.0.tgz", - "integrity": "sha512-Zvtq1xUto4LttpstyOlFum8lKx+i1OmRfg+6A9drFS9iSZsDPMHG4Sof/qwNR4kCU7jBeWFPrY2ocHxiz7cCRw==" - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/inherits-browser": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/inherits-browser/-/inherits-browser-0.0.1.tgz", - "integrity": "sha512-kaDA3DkCdCpvrKIo/1T/3yVn+qpFUHLjYtSHmTYewb+QfjfaQy6FGQ7LwBu7st0tG9UvYad/XAlqQmdIh6CICw==" - }, - "node_modules/interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "peer": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "peer": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "peer": true - }, - "node_modules/json-source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/json-source-map/-/json-source-map-0.6.1.tgz", - "integrity": "sha512-1QoztHPsMQqhDq0hlXY5ZqcEdUzxQEIxgFkKl4WUp2pgShObl+9ovi4kRh2TfvAfxAoHOJ9vIMEqk3k4iex7tg==" - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/matches-selector": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/matches-selector/-/matches-selector-1.2.0.tgz", - "integrity": "sha512-c4vLwYWyl+Ji+U43eU/G5FwxWd4ZH0ePUsFs5y0uwD9HUEFBXUQ1zUUan+78IpRD+y4pUfG0nAzNM292K7ItvA==" - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "peer": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/min-dash": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/min-dash/-/min-dash-3.8.1.tgz", - "integrity": "sha512-evumdlmIlg9mbRVPbC4F5FuRhNmcMS5pvuBUbqb1G9v09Ro0ImPEgz5n3khir83lFok1inKqVDjnKEg3GpDxQg==" - }, - "node_modules/min-dom": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/min-dom/-/min-dom-3.2.1.tgz", - "integrity": "sha512-v6YCmnDzxk4rRJntWTUiwggLupPw/8ZSRqUq0PDaBwVZEO/wYzCH4SKVBV+KkEvf3u0XaWHly5JEosPtqRATZA==", - "dependencies": { - "component-event": "^0.1.4", - "domify": "^1.3.1", - "indexof": "0.0.1", - "matches-selector": "^1.2.0", - "min-dash": "^3.8.1" - } - }, - "node_modules/moddle": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/moddle/-/moddle-5.0.3.tgz", - "integrity": "sha512-EjnQkSaZClHMsM3H/guBy9h7AmHUICH0Pf8H1VnnYGUXy2hkZQU4gqEAyHywJzMRAhYX87pXjH2NtyigF7evkA==", - "dependencies": { - "min-dash": "^3.0.0" - } - }, - "node_modules/moddle-xml": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/moddle-xml/-/moddle-xml-9.0.5.tgz", - "integrity": "sha512-1t9N35ZMQZTYZmRDoh1mBVd0XwLB34BkBywNJ0+YlLLYxaDBjFR/I+fqwsY746ayYPBz6yNRg8JpLyFgNF+eHg==", - "dependencies": { - "min-dash": "^3.5.2", - "moddle": "^5.0.2", - "saxen": "^8.1.2" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "peer": true - }, - "node_modules/node-releases": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", - "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", - "dev": true, - "peer": true - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/object-refs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/object-refs/-/object-refs-0.3.0.tgz", - "integrity": "sha512-eP0ywuoWOaDoiake/6kTJlPJhs+k0qNm4nYRzXLNHj6vh+5M3i9R1epJTdxIPGlhWc4fNRQ7a6XJNCX+/L4FOQ==" - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-intersection": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/path-intersection/-/path-intersection-2.2.1.tgz", - "integrity": "sha512-9u8xvMcSfuOiStv9bPdnRJQhGQXLKurew94n4GPQCdH1nj9QKC9ObbNoIpiRq8skiOBxKkt277PgOoFgAt3/rA==" - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true, - "peer": true - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/preact": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.7.3.tgz", - "integrity": "sha512-giqJXP8VbtA1tyGa3f1n9wiN7PrHtONrDyE3T+ifjr/tTkg+2N4d/6sjC9WyJKv8wM7rOYDveqy5ZoFmYlwo4w==", - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/preact" - } - }, - "node_modules/preact-markup": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/preact-markup/-/preact-markup-2.1.1.tgz", - "integrity": "sha512-8JL2p36mzK8XkspOyhBxUSPjYwMxDM0L5BWBZWxsZMVW8WsGQrYQDgVuDKkRspt2hwrle+Cxr/053hpc9BJwfw==", - "peerDependencies": { - "preact": ">=10" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "peer": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", - "dev": true, - "dependencies": { - "resolve": "^1.9.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peer": true - }, - "node_modules/saxen": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/saxen/-/saxen-8.1.2.tgz", - "integrity": "sha512-xUOiiFbc3Ow7p8KMxwsGICPx46ZQvy3+qfNVhrkwfz3Vvq45eGt98Ft5IQaA1R/7Tb5B5MKh9fUR9x3c3nDTxw==" - }, - "node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "peer": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=" - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "peer": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "peer": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/terser": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.0.tgz", - "integrity": "sha512-JC6qfIEkPBd9j1SMO3Pfn+A6w2kQV54tv+ABQLgZr7dA3k/DL/OBoYSWxzVpZev3J+bUHXfr55L8Mox7AaNo6g==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", - "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", - "dev": true, - "peer": true, - "dependencies": { - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/tiny-svg": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/tiny-svg/-/tiny-svg-2.2.3.tgz", - "integrity": "sha512-u5KGg889pD1W2c9GlLrTnAGzIkAO00/VXZGyzeiGHw+b9er8McLO0SnhxPQQDwDqFO0MrJ825AEsRUoTiDZFuQ==" - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "peer": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", - "dev": true, - "peer": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack": { - "version": "5.72.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz", - "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==", - "dev": true, - "peer": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-cli": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz", - "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==", - "dev": true, - "dependencies": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.1.1", - "@webpack-cli/info": "^1.4.1", - "@webpack-cli/serve": "^1.6.1", - "colorette": "^2.0.14", - "commander": "^7.0.0", - "execa": "^5.0.0", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", - "webpack-merge": "^5.7.3" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "peerDependencies": { - "webpack": "4.x.x || 5.x.x" - }, - "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, - "@webpack-cli/migrate": { - "optional": true - }, - "webpack-bundle-analyzer": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/webpack-cli/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", - "dev": true - }, - "node_modules/zeebe-bpmn-moddle": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/zeebe-bpmn-moddle/-/zeebe-bpmn-moddle-0.12.1.tgz", - "integrity": "sha512-rnUoK+A/gzinOGUlmJKeXmnjorgEm4yf7qgeaowXGZOFtFqtM2lvJ7XYTJNsKClaNfFG245JtKHH3G/caJxE6g==", - "peer": true - } - }, - "dependencies": { - "@bpmn-io/element-templates-validator": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@bpmn-io/element-templates-validator/-/element-templates-validator-0.8.1.tgz", - "integrity": "sha512-cJMVYXxQAkntBZ2Brr76AI8D8xXWNS9GI8YM0h5kjkTihfYC+7FfN744RM1RVx8zJqTzOMf8nkS37t95Re4wvA==", - "requires": { - "@camunda/element-templates-json-schema": "^0.9.1", - "@camunda/zeebe-element-templates-json-schema": "^0.4.1", - "json-source-map": "^0.6.1", - "min-dash": "^3.8.1" - } - }, - "@bpmn-io/extract-process-variables": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/@bpmn-io/extract-process-variables/-/extract-process-variables-0.4.5.tgz", - "integrity": "sha512-LtHx5b9xqS8avRLrq/uTlKhWzMeV3bWQKIdDic2bdo5n9roitX13GRb01u2S0hSsKDWEhXQtydFYN2b6G7bqfw==", - "requires": { - "min-dash": "^3.8.1" - } - }, - "@bpmn-io/properties-panel": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/@bpmn-io/properties-panel/-/properties-panel-0.13.2.tgz", - "integrity": "sha512-S0FUjXApQ8V1tW3TkrmuxXkfiMv6WPdeKkc7DD9tzKTHHnT634GY4pafKPPknxYsLGthUiJghqWbuQahqQjz+g==", - "peer": true, - "requires": { - "classnames": "^2.3.1", - "diagram-js": "^8.1.2", - "min-dash": "^3.7.0", - "min-dom": "^3.1.3" - } - }, - "@camunda/element-templates-json-schema": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@camunda/element-templates-json-schema/-/element-templates-json-schema-0.9.1.tgz", - "integrity": "sha512-hqAOdwf0EdEDughDAfsOWtQQaKx/7m3srVbrUfVZy2Nh2mUc3hyBbkODO4tkMjTKv6I4bw36cyMchzjIEaz4CA==" - }, - "@camunda/zeebe-element-templates-json-schema": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@camunda/zeebe-element-templates-json-schema/-/zeebe-element-templates-json-schema-0.4.1.tgz", - "integrity": "sha512-FAe7auxm+IJiRB0W68VOjBxih6aOJB/0K3nvjO0TtRdyS+a2X1DIDBDtsQO6g+pJDtW6oij0kC1LiBUvm6FmLw==" - }, - "@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "dev": true - }, - "@jridgewell/gen-mapping": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", - "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", - "dev": true, - "peer": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", - "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", - "dev": true, - "peer": true - }, - "@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", - "dev": true, - "peer": true - }, - "@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "peer": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", - "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", - "dev": true, - "peer": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", - "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", - "dev": true, - "peer": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@philippfromme/moddle-helpers": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@philippfromme/moddle-helpers/-/moddle-helpers-0.4.1.tgz", - "integrity": "sha512-6ST9WdafFGh/vxeQP4pwFkcGcqIQJ0mtQSrXwoetTLigCXCcP4UXdXxjcIEwWKoXuexXV/2CgFS0CPENSVcwdg==", - "requires": { - "min-dash": "^3.8.1" - } - }, - "@types/eslint": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz", - "integrity": "sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA==", - "dev": true, - "peer": true, - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", - "dev": true, - "peer": true, - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", - "dev": true, - "peer": true - }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true, - "peer": true - }, - "@types/node": { - "version": "17.0.38", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.38.tgz", - "integrity": "sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g==", - "dev": true, - "peer": true - }, - "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dev": true, - "peer": true, - "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true, - "peer": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true, - "peer": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true, - "peer": true - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dev": true, - "peer": true, - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true, - "peer": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dev": true, - "peer": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dev": true, - "peer": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dev": true, - "peer": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true, - "peer": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dev": true, - "peer": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dev": true, - "peer": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dev": true, - "peer": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dev": true, - "peer": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dev": true, - "peer": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webpack-cli/configtest": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", - "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==", - "dev": true, - "requires": {} - }, - "@webpack-cli/info": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz", - "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==", - "dev": true, - "requires": { - "envinfo": "^7.7.3" - } - }, - "@webpack-cli/serve": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", - "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==", - "dev": true, - "requires": {} - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true, - "peer": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true, - "peer": true - }, - "acorn": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", - "dev": true, - "peer": true - }, - "acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "peer": true, - "requires": {} - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "peer": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peer": true, - "requires": {} - }, - "array-move": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/array-move/-/array-move-3.0.1.tgz", - "integrity": "sha512-H3Of6NIn2nNU1gsVDqDnYKY/LCdWvCMMOWifNGhKcVQgiZ6nOek39aESOvro6zmueP07exSl93YLvkN4fZOkSg==" - }, - "bpmn-js": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/bpmn-js/-/bpmn-js-9.1.0.tgz", - "integrity": "sha512-LFrNVt15hCvTJ7RrdshJeNYyLPAJQKC8sBCXvnFoLuwfuBwNbxkDtaripzrkgCj7X5wyduh+ogZ4KaE5xwsTbA==", - "requires": { - "bpmn-moddle": "^7.1.2", - "css.escape": "^1.5.1", - "diagram-js": "^8.3.0", - "diagram-js-direct-editing": "^1.6.3", - "ids": "^1.0.0", - "inherits": "^2.0.4", - "min-dash": "^3.5.2", - "min-dom": "^3.2.0", - "object-refs": "^0.3.0", - "tiny-svg": "^2.2.2" - } - }, - "bpmn-js-properties-panel": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/bpmn-js-properties-panel/-/bpmn-js-properties-panel-1.1.1.tgz", - "integrity": "sha512-FIxg3yIeKtYzDFLqI9GzhYBYDh12WtyvHFOSl4bSlDUQJIs31Xe7yobECEZNQ+00XtmtKUK96ikHUti5YydgDQ==", - "requires": { - "@bpmn-io/element-templates-validator": "^0.8.1", - "@bpmn-io/extract-process-variables": "^0.4.5", - "@philippfromme/moddle-helpers": "^0.4.1", - "array-move": "^3.0.1", - "classnames": "^2.3.1", - "ids": "^1.0.0", - "min-dash": "^3.8.1", - "min-dom": "^3.1.3", - "preact-markup": "^2.1.1", - "semver-compare": "^1.0.0" - } - }, - "bpmn-moddle": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/bpmn-moddle/-/bpmn-moddle-7.1.2.tgz", - "integrity": "sha512-Sax4LokRCTqlg26njjULN3ZGtCmwH5gZVUZTRF0jwJk+YpMQhSfSoUECxjNv8OROoLxu8Z+MjdOHIxgvJf7KwA==", - "requires": { - "min-dash": "^3.5.2", - "moddle": "^5.0.2", - "moddle-xml": "^9.0.5" - } - }, - "browserslist": { - "version": "4.20.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", - "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", - "dev": true, - "peer": true, - "requires": { - "caniuse-lite": "^1.0.30001332", - "electron-to-chromium": "^1.4.118", - "escalade": "^3.1.1", - "node-releases": "^2.0.3", - "picocolors": "^1.0.0" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "peer": true - }, - "camunda-bpmn-js-behaviors": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/camunda-bpmn-js-behaviors/-/camunda-bpmn-js-behaviors-0.1.0.tgz", - "integrity": "sha512-YJs4kAkRhZ1GyE4VVPTJlZ/GjuDHnSGvzuLTa87HIfpEonVMHsmRrQL0Gr/bkSVcQaA4s6XB0XKV6rz32LHNUA==", - "peer": true, - "requires": { - "ids": "^1.0.0", - "min-dash": "^3.7.0" - } - }, - "camunda-bpmn-moddle": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/camunda-bpmn-moddle/-/camunda-bpmn-moddle-6.1.2.tgz", - "integrity": "sha512-DfhOTeq8oN01cB5sLE6Rq34/9xGD15/Y14pEM+YBIjgvV6Rclh+BgIa/2aRMm8An4Kc/itm2tECYiDr8p/FyTQ==", - "peer": true, - "requires": { - "min-dash": "^3.8.1" - } - }, - "caniuse-lite": { - "version": "1.0.30001344", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz", - "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==", - "dev": true, - "peer": true - }, - "chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true, - "peer": true - }, - "classnames": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", - "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" - }, - "clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - } - }, - "colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", - "dev": true - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "peer": true - }, - "component-event": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/component-event/-/component-event-0.1.4.tgz", - "integrity": "sha512-GMwOG8MnUHP1l8DZx1ztFO0SJTFnIzZnBDkXAj8RM2ntV2A6ALlDxgbMY1Fvxlg6WPQ+5IM/a6vg4PEYbjg/Rw==" - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=" - }, - "diagram-js": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/diagram-js/-/diagram-js-8.5.0.tgz", - "integrity": "sha512-UHA/Zfs7kG22M9wXAifAyPb2OZ4lG4lFi0CZ0GC6/lXmOsSHwHVZ1s/h9UqaIXnzIKW8SnZoP3Rwqel1ZhZLzg==", - "requires": { - "css.escape": "^1.5.1", - "didi": "^8.0.0", - "hammerjs": "^2.0.1", - "inherits-browser": "0.0.1", - "min-dash": "^3.5.2", - "min-dom": "^3.2.0", - "object-refs": "^0.3.0", - "path-intersection": "^2.2.1", - "tiny-svg": "^2.2.2" - } - }, - "diagram-js-direct-editing": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/diagram-js-direct-editing/-/diagram-js-direct-editing-1.7.0.tgz", - "integrity": "sha512-ZfTLF4hdWr7NSoruwxGvVmu7aVaUjWRXjwgK5dx58LbXAsNjBS3Ap7zjVuGxjWUpCZ/MMwyZ00lpTHPH2P7BFQ==", - "requires": { - "min-dash": "^3.5.2", - "min-dom": "^3.1.3" - } - }, - "didi": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/didi/-/didi-8.0.0.tgz", - "integrity": "sha512-PwqTBaYzzfJSyxvpXPcTWF6nDdCKx2mFAU5eup1ZSb5wbaAS9a/HiKdtcAUdie/VMLHoFI50jkYZcA+bhUOugw==" - }, - "domify": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/domify/-/domify-1.4.1.tgz", - "integrity": "sha512-x18nuiDHMCZGXr4KJSRMf/TWYtiaRo6RX8KN9fEbW54mvbQ6pieUuerC2ahBg+kEp1wycFj8MPUI0WkIOw5E9w==" - }, - "electron-to-chromium": { - "version": "1.4.143", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.143.tgz", - "integrity": "sha512-2hIgvu0+pDfXIqmVmV5X6iwMjQ2KxDsWKwM+oI1fABEOy/Dqmll0QJRmIQ3rm+XaoUa/qKrmy5h7LSTFQ6Ldzg==", - "dev": true, - "peer": true - }, - "enhanced-resolve": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", - "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", - "dev": true, - "peer": true, - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", - "dev": true - }, - "es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", - "dev": true, - "peer": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "peer": true - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "peer": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "peer": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "peer": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "peer": true - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "peer": true - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "peer": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "peer": true - }, - "fastest-levenshtein": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", - "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true, - "peer": true - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true, - "peer": true - }, - "hammerjs": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", - "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "peer": true - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "ids": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ids/-/ids-1.0.0.tgz", - "integrity": "sha512-Zvtq1xUto4LttpstyOlFum8lKx+i1OmRfg+6A9drFS9iSZsDPMHG4Sof/qwNR4kCU7jBeWFPrY2ocHxiz7cCRw==" - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "inherits-browser": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/inherits-browser/-/inherits-browser-0.0.1.tgz", - "integrity": "sha512-kaDA3DkCdCpvrKIo/1T/3yVn+qpFUHLjYtSHmTYewb+QfjfaQy6FGQ7LwBu7st0tG9UvYad/XAlqQmdIh6CICw==" - }, - "interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "dev": true - }, - "is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true - }, - "jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "peer": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "peer": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "peer": true - }, - "json-source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/json-source-map/-/json-source-map-0.6.1.tgz", - "integrity": "sha512-1QoztHPsMQqhDq0hlXY5ZqcEdUzxQEIxgFkKl4WUp2pgShObl+9ovi4kRh2TfvAfxAoHOJ9vIMEqk3k4iex7tg==" - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, - "peer": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "matches-selector": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/matches-selector/-/matches-selector-1.2.0.tgz", - "integrity": "sha512-c4vLwYWyl+Ji+U43eU/G5FwxWd4ZH0ePUsFs5y0uwD9HUEFBXUQ1zUUan+78IpRD+y4pUfG0nAzNM292K7ItvA==" - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "peer": true - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "peer": true, - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "min-dash": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/min-dash/-/min-dash-3.8.1.tgz", - "integrity": "sha512-evumdlmIlg9mbRVPbC4F5FuRhNmcMS5pvuBUbqb1G9v09Ro0ImPEgz5n3khir83lFok1inKqVDjnKEg3GpDxQg==" - }, - "min-dom": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/min-dom/-/min-dom-3.2.1.tgz", - "integrity": "sha512-v6YCmnDzxk4rRJntWTUiwggLupPw/8ZSRqUq0PDaBwVZEO/wYzCH4SKVBV+KkEvf3u0XaWHly5JEosPtqRATZA==", - "requires": { - "component-event": "^0.1.4", - "domify": "^1.3.1", - "indexof": "0.0.1", - "matches-selector": "^1.2.0", - "min-dash": "^3.8.1" - } - }, - "moddle": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/moddle/-/moddle-5.0.3.tgz", - "integrity": "sha512-EjnQkSaZClHMsM3H/guBy9h7AmHUICH0Pf8H1VnnYGUXy2hkZQU4gqEAyHywJzMRAhYX87pXjH2NtyigF7evkA==", - "requires": { - "min-dash": "^3.0.0" - } - }, - "moddle-xml": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/moddle-xml/-/moddle-xml-9.0.5.tgz", - "integrity": "sha512-1t9N35ZMQZTYZmRDoh1mBVd0XwLB34BkBywNJ0+YlLLYxaDBjFR/I+fqwsY746ayYPBz6yNRg8JpLyFgNF+eHg==", - "requires": { - "min-dash": "^3.5.2", - "moddle": "^5.0.2", - "saxen": "^8.1.2" - } - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "peer": true - }, - "node-releases": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", - "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", - "dev": true, - "peer": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "object-refs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/object-refs/-/object-refs-0.3.0.tgz", - "integrity": "sha512-eP0ywuoWOaDoiake/6kTJlPJhs+k0qNm4nYRzXLNHj6vh+5M3i9R1epJTdxIPGlhWc4fNRQ7a6XJNCX+/L4FOQ==" - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-intersection": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/path-intersection/-/path-intersection-2.2.1.tgz", - "integrity": "sha512-9u8xvMcSfuOiStv9bPdnRJQhGQXLKurew94n4GPQCdH1nj9QKC9ObbNoIpiRq8skiOBxKkt277PgOoFgAt3/rA==" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true, - "peer": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "preact": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.7.3.tgz", - "integrity": "sha512-giqJXP8VbtA1tyGa3f1n9wiN7PrHtONrDyE3T+ifjr/tTkg+2N4d/6sjC9WyJKv8wM7rOYDveqy5ZoFmYlwo4w==", - "peer": true - }, - "preact-markup": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/preact-markup/-/preact-markup-2.1.1.tgz", - "integrity": "sha512-8JL2p36mzK8XkspOyhBxUSPjYwMxDM0L5BWBZWxsZMVW8WsGQrYQDgVuDKkRspt2hwrle+Cxr/053hpc9BJwfw==", - "requires": {} - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "peer": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "peer": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", - "dev": true, - "requires": { - "resolve": "^1.9.0" - } - }, - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "peer": true - }, - "saxen": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/saxen/-/saxen-8.1.2.tgz", - "integrity": "sha512-xUOiiFbc3Ow7p8KMxwsGICPx46ZQvy3+qfNVhrkwfz3Vvq45eGt98Ft5IQaA1R/7Tb5B5MKh9fUR9x3c3nDTxw==" - }, - "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "peer": true, - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=" - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "peer": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "peer": true - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "peer": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "peer": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "peer": true - }, - "terser": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.0.tgz", - "integrity": "sha512-JC6qfIEkPBd9j1SMO3Pfn+A6w2kQV54tv+ABQLgZr7dA3k/DL/OBoYSWxzVpZev3J+bUHXfr55L8Mox7AaNo6g==", - "dev": true, - "peer": true, - "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - } - }, - "terser-webpack-plugin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", - "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", - "dev": true, - "peer": true, - "requires": { - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" - } - }, - "tiny-svg": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/tiny-svg/-/tiny-svg-2.2.3.tgz", - "integrity": "sha512-u5KGg889pD1W2c9GlLrTnAGzIkAO00/VXZGyzeiGHw+b9er8McLO0SnhxPQQDwDqFO0MrJ825AEsRUoTiDZFuQ==" - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "peer": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", - "dev": true, - "peer": true, - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - } - }, - "webpack": { - "version": "5.72.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz", - "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==", - "dev": true, - "peer": true, - "requires": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", - "webpack-sources": "^3.2.3" - } - }, - "webpack-cli": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz", - "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==", - "dev": true, - "requires": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.1.1", - "@webpack-cli/info": "^1.4.1", - "@webpack-cli/serve": "^1.6.1", - "colorette": "^2.0.14", - "commander": "^7.0.0", - "execa": "^5.0.0", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", - "webpack-merge": "^5.7.3" - }, - "dependencies": { - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true - } - } - }, - "webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", - "dev": true, - "requires": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - } - }, - "webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "peer": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", - "dev": true - }, - "zeebe-bpmn-moddle": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/zeebe-bpmn-moddle/-/zeebe-bpmn-moddle-0.12.1.tgz", - "integrity": "sha512-rnUoK+A/gzinOGUlmJKeXmnjorgEm4yf7qgeaowXGZOFtFqtM2lvJ7XYTJNsKClaNfFG245JtKHH3G/caJxE6g==", - "peer": true - } - } -} diff --git a/src/spiffworkflow_backend/routes/admin_blueprint/static/package.json b/src/spiffworkflow_backend/routes/admin_blueprint/static/package.json deleted file mode 100644 index bee0dcf5d..000000000 --- a/src/spiffworkflow_backend/routes/admin_blueprint/static/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "spiffworkflow-backend", - "version": "0.0.0", - "description": "Serve up Spiff Workflows to the World!", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "ISC", - "dependencies": { - "bpmn-js": "^9.1.0", - "bpmn-js-properties-panel": "^1.1.1" - }, - "devDependencies": { - "webpack-cli": "^4.9.2" - } -} diff --git a/src/spiffworkflow_backend/routes/admin_blueprint/static/style.css b/src/spiffworkflow_backend/routes/admin_blueprint/static/style.css deleted file mode 100644 index b534fcd55..000000000 --- a/src/spiffworkflow_backend/routes/admin_blueprint/static/style.css +++ /dev/null @@ -1,2 +0,0 @@ -.example { -} diff --git a/src/spiffworkflow_backend/routes/admin_blueprint/templates/layout.html b/src/spiffworkflow_backend/routes/admin_blueprint/templates/layout.html deleted file mode 100644 index d1521fdd9..000000000 --- a/src/spiffworkflow_backend/routes/admin_blueprint/templates/layout.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - {% block head %} - - {% block title %}{% endblock %} - {% endblock %} - - -

{{ self.title() }}

- {% with messages = get_flashed_messages(with_categories=true) %} {% if - messages %} -
    - {% for category, message in messages %} -
  • {{ message }}
  • - {% endfor %} -
- {% endif %} {% endwith %} {% block content %}{% endblock %} - - diff --git a/src/spiffworkflow_backend/routes/admin_blueprint/templates/process_group_list.html b/src/spiffworkflow_backend/routes/admin_blueprint/templates/process_group_list.html deleted file mode 100644 index f6eb8f58b..000000000 --- a/src/spiffworkflow_backend/routes/admin_blueprint/templates/process_group_list.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "layout.html" %} {% block title %}Process Groups{% endblock %} {% -block content %} - - - {# here we iterate over every item in our list#} {% for process_group in - process_groups %} - - - - {% endfor %} - -
- {{ process_group.display_name }} -
-{% endblock %} diff --git a/src/spiffworkflow_backend/routes/admin_blueprint/templates/process_group_show.html b/src/spiffworkflow_backend/routes/admin_blueprint/templates/process_group_show.html deleted file mode 100644 index 2a41abe91..000000000 --- a/src/spiffworkflow_backend/routes/admin_blueprint/templates/process_group_show.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends "layout.html" %} -{% block title %}Process Group: {{ process_group.id }}{% endblock %} -{% block content %} - - - - {# here we iterate over every item in our list#} - {% for process_model in process_group.process_models %} - - - - {% endfor %} - -
- {{ process_model.display_name }} -
-{% endblock %} diff --git a/src/spiffworkflow_backend/routes/admin_blueprint/templates/process_model_edit.html b/src/spiffworkflow_backend/routes/admin_blueprint/templates/process_model_edit.html deleted file mode 100644 index 8dca623aa..000000000 --- a/src/spiffworkflow_backend/routes/admin_blueprint/templates/process_model_edit.html +++ /dev/null @@ -1,167 +0,0 @@ -{% extends "layout.html" %} {% block title %} - Process Model Edit: {{ process_model.id }} -{% endblock %} - -{% block head %} - - - - - - - - - - - - - - - - - - - -{% endblock %} - -{% block content %} -
{{ result }}
- - - -
-
- - - - -{% endblock %} diff --git a/src/spiffworkflow_backend/routes/admin_blueprint/templates/process_model_show.html b/src/spiffworkflow_backend/routes/admin_blueprint/templates/process_model_show.html deleted file mode 100644 index 5eedf1de1..000000000 --- a/src/spiffworkflow_backend/routes/admin_blueprint/templates/process_model_show.html +++ /dev/null @@ -1,159 +0,0 @@ -{% extends "layout.html" %} {% block title %}Process Model: {{ process_model.id -}}{% endblock %} {% block head %} {{ super() }} - - - - - - - - - - - - - - - - - - -{% endblock %} {% block content %} -
{{ result }}
- - - - -{% if files %} -

BPMN Files

-
    - {% for file in files %} -
  • - {{ file.name }} - {% if file.name == current_file_name %} (current) {% endif %} -
  • - {% endfor %} -
-{% endif %} - -
- - -
- -
- - - - -{% endblock %} diff --git a/src/spiffworkflow_backend/routes/messages_controller.py b/src/spiffworkflow_backend/routes/messages_controller.py index 30456c934..0db93a4a6 100644 --- a/src/spiffworkflow_backend/routes/messages_controller.py +++ b/src/spiffworkflow_backend/routes/messages_controller.py @@ -9,8 +9,8 @@ from flask import g from flask import jsonify from flask import make_response from flask.wrappers import Response -from flask_bpmn.api.api_error import ApiError +from spiffworkflow_backend.exceptions.api_error import ApiError from spiffworkflow_backend.models.message_correlation import MessageCorrelationModel from spiffworkflow_backend.models.message_instance import MessageInstanceModel from spiffworkflow_backend.models.message_model import MessageModel diff --git a/src/spiffworkflow_backend/routes/openid_blueprint/templates/login.html b/src/spiffworkflow_backend/routes/openid_blueprint/templates/login.html index d9b8b901a..858355c36 100644 --- a/src/spiffworkflow_backend/routes/openid_blueprint/templates/login.html +++ b/src/spiffworkflow_backend/routes/openid_blueprint/templates/login.html @@ -13,16 +13,18 @@
{{error_message}}