From 56368d1de75cb4a98aa63bc69e93f249ebec8291 Mon Sep 17 00:00:00 2001 From: iglocska Date: Fri, 29 May 2020 13:41:58 +0200 Subject: [PATCH] new: [initial] import of the project files - Cerebrate v0.1 initial WIP version [Features] - initial version of TrustDB - Organisation - User scope - Alignments between Users and Organisations - semi-implemented encryption key store [Internals] - MISP systems transposed to CakePHP4 / Bootstrap 4 / Cerebrate - UI factories - Index factories - Form factories - internal: - RestResponse library - ACL library in progress - new clean UI using BS4 - New systems: - UI factories - view factories - Datamodel import/cleaning via SQL scripts --- app/.editorconfig | 23 + app/.gitattributes | 54 + app/.gitignore | 43 + app/.htaccess | 5 + app/INSTALL/MYSQL.sql | 176 + app/INSTALL/clean.sql | 14 + app/INSTALL/data.sql | 6 + app/README.md | 53 + app/bin/cake | 75 + app/bin/cake.bat | 27 + app/bin/cake.php | 12 + app/composer.json | 56 + app/composer.lock | 4548 +++++++ app/config/.env.example | 38 + app/config/app.php | 401 + app/config/app_local.example.php | 92 + app/config/bootstrap.php | 215 + app/config/bootstrap_cli.php | 31 + app/config/cerebrate-pagination-templates.php | 11 + app/config/paths.php | 94 + app/config/requirements.php | 46 + app/config/routes.php | 99 + app/config/schema/i18n.sql | 18 + app/config/schema/sessions.sql | 15 + app/index.php | 16 + app/phpunit.xml.dist | 40 + app/plugins/.gitkeep | 0 app/resources/.gitkeep | 0 app/src/Application.php | 108 + app/src/Command/ConsoleCommand.php | 86 + app/src/Console/Installer.php | 246 + app/src/Controller/AlignmentsController.php | 130 + app/src/Controller/AppController.php | 104 + app/src/Controller/Component/.gitkeep | 0 app/src/Controller/Component/ACLComponent.php | 875 ++ .../Component/RestResponseComponent.php | 1782 +++ .../Controller/EncryptionKeysController.php | 117 + app/src/Controller/ErrorController.php | 70 + app/src/Controller/IndividualsController.php | 155 + .../Controller/OrganisationsController.php | 153 + app/src/Controller/PagesController.php | 75 + app/src/Model/Behavior/.gitkeep | 0 app/src/Model/Entity/.gitkeep | 0 app/src/Model/Entity/Alignment.php | 11 + app/src/Model/Entity/AppModel.php | 10 + app/src/Model/Entity/EncryptionKey.php | 11 + app/src/Model/Entity/Individual.php | 11 + app/src/Model/Entity/Orgnaisation.php | 11 + app/src/Model/Table/.gitkeep | 0 app/src/Model/Table/AlignmentsTable.php | 26 + app/src/Model/Table/AppTable.php | 13 + app/src/Model/Table/EncryptionKeysTable.php | 41 + app/src/Model/Table/IndividualsTable.php | 32 + app/src/Model/Table/OrganisationsTable.php | 32 + .../Model/Validation/ValidationCollection.php | 13 + app/src/View/AjaxView.php | 46 + app/src/View/AppView.php | 45 + app/src/View/Cell/.gitkeep | 0 app/src/View/Helper/.gitkeep | 0 app/src/View/Helper/FontAwesomeHelper.php | 450 + app/src/View/Helper/HashHelper.php | 14 + app/templates/Alignments/add.php | 23 + app/templates/EncryptionKeys/add.php | 30 + app/templates/Error/error400.php | 38 + app/templates/Error/error500.php | 42 + app/templates/Individuals/add.php | 35 + app/templates/Individuals/index.php | 74 + app/templates/Individuals/view.php | 41 + app/templates/Organisations/add.php | 42 + app/templates/Organisations/index.php | 84 + app/templates/Organisations/view.php | 49 + app/templates/Pages/home.php | 222 + app/templates/cell/.gitkeep | 1 + app/templates/element/flash/default.php | 20 + app/templates/element/flash/error.php | 16 + app/templates/element/flash/success.php | 16 + .../Form/Fields/checkboxField.php | 8 + .../Form/Fields/genericField.php | 9 + .../genericElements/Form/Fields/uuidField.php | 42 + .../element/genericElements/Form/formInfo.php | 47 + .../genericElements/Form/genericForm.php | 160 + .../genericElements/Form/submitButton.php | 17 + .../IndexTable/Fields/actions.php | 96 + .../IndexTable/Fields/alignments.php | 43 + .../IndexTable/Fields/array_lookup_field.php | 4 + .../IndexTable/Fields/boolean.php | 57 + .../IndexTable/Fields/caching.php | 32 + .../IndexTable/Fields/correlations.php | 20 + .../IndexTable/Fields/count_summary.php | 25 + .../IndexTable/Fields/datetime.php | 26 + .../IndexTable/Fields/distribution_levels.php | 15 + .../IndexTable/Fields/generic_field.php | 37 + .../IndexTable/Fields/icon.php | 5 + .../IndexTable/Fields/json.php | 16 + .../IndexTable/Fields/links.php | 47 + .../IndexTable/Fields/list.php | 16 + .../genericElements/IndexTable/Fields/org.php | 38 + .../IndexTable/Fields/role.php | 22 + .../IndexTable/Fields/selector.php | 20 + .../IndexTable/Fields/self_registration.php | 17 + .../IndexTable/Fields/sparkline.php | 4 + .../IndexTable/Fields/tags.php | 17 + .../IndexTable/Fields/target_event.php | 33 + .../IndexTable/Fields/tester.php | 30 + .../IndexTable/Fields/timestamp.php | 7 + .../IndexTable/Fields/toggle.php | 59 + .../genericElements/IndexTable/headers.php | 51 + .../IndexTable/index_table.php | 125 + .../genericElements/IndexTable/pagination.php | 36 + .../IndexTable/pagination_counter.php | 17 + .../IndexTable/pagination_limiter.php | 11 + .../IndexTable/pagination_links.php | 8 + .../genericElements/IndexTable/row.php | 63 + .../ListTopBar/element_embedded.php | 47 + .../ListTopBar/element_group.php | 33 + .../ListTopBar/element_simple.php | 56 + .../ListTopBar/group_live_search.php | 13 + .../ListTopBar/group_search.php | 58 + .../ListTopBar/group_simple.php | 13 + .../genericElements/ListTopBar/scaffold.php | 17 + .../genericElements/SideMenu/side_menu.php | 106 + .../SingleViews/Fields/alignmentField.php | 51 + .../SingleViews/Fields/genericField.php | 3 + .../genericElements/SingleViews/child.php | 25 + .../SingleViews/single_view.php | 64 + .../element/genericElements/footer.php | 3 + .../element/genericElements/genericModal.php | 24 + .../element/genericElements/header.php | 146 + app/templates/email/html/default.php | 21 + app/templates/email/text/default.php | 17 + app/templates/genericTemplates/delete.php | 29 + app/templates/layout/ajax.php | 17 + app/templates/layout/default.php | 63 + app/templates/layout/email/html/default.php | 25 + app/templates/layout/email/text/default.php | 17 + app/templates/layout/error.php | 43 + app/tests/Fixture/.gitkeep | 0 app/tests/TestCase/ApplicationTest.php | 87 + .../TestCase/Controller/Component/.gitkeep | 0 .../Controller/PagesControllerTest.php | 126 + app/tests/TestCase/Model/Behavior/.gitkeep | 0 app/tests/TestCase/View/Helper/.gitkeep | 0 app/tests/bootstrap.php | 52 + app/webroot/.htaccess | 12 + app/webroot/bootstrap | 1 + app/webroot/css/bootstrap.css | 10224 ++++++++++++++++ app/webroot/css/cake.css | 177 + app/webroot/css/font-awesome.css | 4336 +++++++ app/webroot/css/home.css | 72 + app/webroot/css/main.css | 111 + app/webroot/css/milligram.min.css | 11 + app/webroot/debug_kit | 1 + app/webroot/favicon.ico | Bin 0 -> 1470 bytes app/webroot/font/cakedingbats-webfont.eot | Bin 0 -> 75538 bytes app/webroot/font/cakedingbats-webfont.svg | 78 + app/webroot/font/cakedingbats-webfont.ttf | Bin 0 -> 75412 bytes app/webroot/font/cakedingbats-webfont.woff | Bin 0 -> 43484 bytes app/webroot/font/cakedingbats-webfont.woff2 | Bin 0 -> 35456 bytes app/webroot/img/cake-logo.png | Bin 0 -> 2683 bytes app/webroot/img/cake.icon.png | Bin 0 -> 943 bytes app/webroot/img/cake.logo.svg | 41 + app/webroot/img/cake.power.gif | Bin 0 -> 201 bytes app/webroot/img/favicon.ico | Bin 0 -> 1470 bytes app/webroot/img/zicon.png | Bin 0 -> 695 bytes app/webroot/index.php | 40 + app/webroot/js/.gitkeep | 0 app/webroot/js/bootstrap.bundle.js | 7134 +++++++++++ app/webroot/js/bootstrap.js | 4521 +++++++ app/webroot/js/font-awesome-helper.js | 433 + app/webroot/js/jquery-3.4.1.slim.min.js | 2 + app/webroot/js/jquery-3.5.1.min.js | 2 + app/webroot/js/main.js | 23 + app/webroot/js/popper.min.js | 5 + app/webroot/scss/custom.scss | 1 + app/webroot/webfonts/fa-brands-400.eot | Bin 0 -> 129648 bytes app/webroot/webfonts/fa-brands-400.svg | 3452 ++++++ app/webroot/webfonts/fa-brands-400.ttf | Bin 0 -> 129344 bytes app/webroot/webfonts/fa-brands-400.woff | Bin 0 -> 87544 bytes app/webroot/webfonts/fa-brands-400.woff2 | Bin 0 -> 74656 bytes app/webroot/webfonts/fa-regular-400.eot | Bin 0 -> 34388 bytes app/webroot/webfonts/fa-regular-400.svg | 803 ++ app/webroot/webfonts/fa-regular-400.ttf | Bin 0 -> 34092 bytes app/webroot/webfonts/fa-regular-400.woff | Bin 0 -> 16804 bytes app/webroot/webfonts/fa-regular-400.woff2 | Bin 0 -> 13584 bytes app/webroot/webfonts/fa-solid-900.eot | Bin 0 -> 186708 bytes app/webroot/webfonts/fa-solid-900.svg | 4527 +++++++ app/webroot/webfonts/fa-solid-900.ttf | Bin 0 -> 186424 bytes app/webroot/webfonts/fa-solid-900.woff | Bin 0 -> 96256 bytes app/webroot/webfonts/fa-solid-900.woff2 | Bin 0 -> 74328 bytes 189 files changed, 50051 insertions(+) create mode 100644 app/.editorconfig create mode 100644 app/.gitattributes create mode 100644 app/.gitignore create mode 100644 app/.htaccess create mode 100644 app/INSTALL/MYSQL.sql create mode 100644 app/INSTALL/clean.sql create mode 100644 app/INSTALL/data.sql create mode 100644 app/README.md create mode 100755 app/bin/cake create mode 100644 app/bin/cake.bat create mode 100644 app/bin/cake.php create mode 100644 app/composer.json create mode 100644 app/composer.lock create mode 100644 app/config/.env.example create mode 100644 app/config/app.php create mode 100644 app/config/app_local.example.php create mode 100644 app/config/bootstrap.php create mode 100644 app/config/bootstrap_cli.php create mode 100644 app/config/cerebrate-pagination-templates.php create mode 100644 app/config/paths.php create mode 100644 app/config/requirements.php create mode 100644 app/config/routes.php create mode 100644 app/config/schema/i18n.sql create mode 100644 app/config/schema/sessions.sql create mode 100644 app/index.php create mode 100644 app/phpunit.xml.dist create mode 100644 app/plugins/.gitkeep create mode 100644 app/resources/.gitkeep create mode 100644 app/src/Application.php create mode 100644 app/src/Command/ConsoleCommand.php create mode 100644 app/src/Console/Installer.php create mode 100644 app/src/Controller/AlignmentsController.php create mode 100644 app/src/Controller/AppController.php create mode 100644 app/src/Controller/Component/.gitkeep create mode 100644 app/src/Controller/Component/ACLComponent.php create mode 100644 app/src/Controller/Component/RestResponseComponent.php create mode 100644 app/src/Controller/EncryptionKeysController.php create mode 100644 app/src/Controller/ErrorController.php create mode 100644 app/src/Controller/IndividualsController.php create mode 100644 app/src/Controller/OrganisationsController.php create mode 100644 app/src/Controller/PagesController.php create mode 100644 app/src/Model/Behavior/.gitkeep create mode 100644 app/src/Model/Entity/.gitkeep create mode 100644 app/src/Model/Entity/Alignment.php create mode 100644 app/src/Model/Entity/AppModel.php create mode 100644 app/src/Model/Entity/EncryptionKey.php create mode 100644 app/src/Model/Entity/Individual.php create mode 100644 app/src/Model/Entity/Orgnaisation.php create mode 100644 app/src/Model/Table/.gitkeep create mode 100644 app/src/Model/Table/AlignmentsTable.php create mode 100644 app/src/Model/Table/AppTable.php create mode 100644 app/src/Model/Table/EncryptionKeysTable.php create mode 100644 app/src/Model/Table/IndividualsTable.php create mode 100644 app/src/Model/Table/OrganisationsTable.php create mode 100644 app/src/Model/Validation/ValidationCollection.php create mode 100644 app/src/View/AjaxView.php create mode 100644 app/src/View/AppView.php create mode 100644 app/src/View/Cell/.gitkeep create mode 100644 app/src/View/Helper/.gitkeep create mode 100644 app/src/View/Helper/FontAwesomeHelper.php create mode 100644 app/src/View/Helper/HashHelper.php create mode 100644 app/templates/Alignments/add.php create mode 100644 app/templates/EncryptionKeys/add.php create mode 100644 app/templates/Error/error400.php create mode 100644 app/templates/Error/error500.php create mode 100644 app/templates/Individuals/add.php create mode 100644 app/templates/Individuals/index.php create mode 100644 app/templates/Individuals/view.php create mode 100644 app/templates/Organisations/add.php create mode 100644 app/templates/Organisations/index.php create mode 100644 app/templates/Organisations/view.php create mode 100644 app/templates/Pages/home.php create mode 100644 app/templates/cell/.gitkeep create mode 100644 app/templates/element/flash/default.php create mode 100644 app/templates/element/flash/error.php create mode 100644 app/templates/element/flash/success.php create mode 100644 app/templates/element/genericElements/Form/Fields/checkboxField.php create mode 100644 app/templates/element/genericElements/Form/Fields/genericField.php create mode 100644 app/templates/element/genericElements/Form/Fields/uuidField.php create mode 100644 app/templates/element/genericElements/Form/formInfo.php create mode 100644 app/templates/element/genericElements/Form/genericForm.php create mode 100644 app/templates/element/genericElements/Form/submitButton.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/actions.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/alignments.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/array_lookup_field.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/boolean.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/caching.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/correlations.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/count_summary.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/datetime.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/distribution_levels.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/generic_field.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/icon.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/json.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/links.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/list.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/org.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/role.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/selector.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/self_registration.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/sparkline.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/tags.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/target_event.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/tester.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/timestamp.php create mode 100644 app/templates/element/genericElements/IndexTable/Fields/toggle.php create mode 100644 app/templates/element/genericElements/IndexTable/headers.php create mode 100644 app/templates/element/genericElements/IndexTable/index_table.php create mode 100644 app/templates/element/genericElements/IndexTable/pagination.php create mode 100644 app/templates/element/genericElements/IndexTable/pagination_counter.php create mode 100644 app/templates/element/genericElements/IndexTable/pagination_limiter.php create mode 100644 app/templates/element/genericElements/IndexTable/pagination_links.php create mode 100644 app/templates/element/genericElements/IndexTable/row.php create mode 100644 app/templates/element/genericElements/ListTopBar/element_embedded.php create mode 100644 app/templates/element/genericElements/ListTopBar/element_group.php create mode 100644 app/templates/element/genericElements/ListTopBar/element_simple.php create mode 100644 app/templates/element/genericElements/ListTopBar/group_live_search.php create mode 100644 app/templates/element/genericElements/ListTopBar/group_search.php create mode 100644 app/templates/element/genericElements/ListTopBar/group_simple.php create mode 100644 app/templates/element/genericElements/ListTopBar/scaffold.php create mode 100644 app/templates/element/genericElements/SideMenu/side_menu.php create mode 100644 app/templates/element/genericElements/SingleViews/Fields/alignmentField.php create mode 100644 app/templates/element/genericElements/SingleViews/Fields/genericField.php create mode 100644 app/templates/element/genericElements/SingleViews/child.php create mode 100644 app/templates/element/genericElements/SingleViews/single_view.php create mode 100644 app/templates/element/genericElements/footer.php create mode 100644 app/templates/element/genericElements/genericModal.php create mode 100644 app/templates/element/genericElements/header.php create mode 100644 app/templates/email/html/default.php create mode 100644 app/templates/email/text/default.php create mode 100644 app/templates/genericTemplates/delete.php create mode 100644 app/templates/layout/ajax.php create mode 100644 app/templates/layout/default.php create mode 100644 app/templates/layout/email/html/default.php create mode 100644 app/templates/layout/email/text/default.php create mode 100644 app/templates/layout/error.php create mode 100644 app/tests/Fixture/.gitkeep create mode 100644 app/tests/TestCase/ApplicationTest.php create mode 100644 app/tests/TestCase/Controller/Component/.gitkeep create mode 100644 app/tests/TestCase/Controller/PagesControllerTest.php create mode 100644 app/tests/TestCase/Model/Behavior/.gitkeep create mode 100644 app/tests/TestCase/View/Helper/.gitkeep create mode 100644 app/tests/bootstrap.php create mode 100644 app/webroot/.htaccess create mode 160000 app/webroot/bootstrap create mode 100644 app/webroot/css/bootstrap.css create mode 100644 app/webroot/css/cake.css create mode 100644 app/webroot/css/font-awesome.css create mode 100644 app/webroot/css/home.css create mode 100644 app/webroot/css/main.css create mode 100644 app/webroot/css/milligram.min.css create mode 120000 app/webroot/debug_kit create mode 100644 app/webroot/favicon.ico create mode 100644 app/webroot/font/cakedingbats-webfont.eot create mode 100644 app/webroot/font/cakedingbats-webfont.svg create mode 100644 app/webroot/font/cakedingbats-webfont.ttf create mode 100644 app/webroot/font/cakedingbats-webfont.woff create mode 100644 app/webroot/font/cakedingbats-webfont.woff2 create mode 100644 app/webroot/img/cake-logo.png create mode 100644 app/webroot/img/cake.icon.png create mode 100644 app/webroot/img/cake.logo.svg create mode 100644 app/webroot/img/cake.power.gif create mode 100644 app/webroot/img/favicon.ico create mode 100644 app/webroot/img/zicon.png create mode 100644 app/webroot/index.php create mode 100644 app/webroot/js/.gitkeep create mode 100644 app/webroot/js/bootstrap.bundle.js create mode 100644 app/webroot/js/bootstrap.js create mode 100644 app/webroot/js/font-awesome-helper.js create mode 100644 app/webroot/js/jquery-3.4.1.slim.min.js create mode 100644 app/webroot/js/jquery-3.5.1.min.js create mode 100644 app/webroot/js/main.js create mode 100644 app/webroot/js/popper.min.js create mode 100644 app/webroot/scss/custom.scss create mode 100644 app/webroot/webfonts/fa-brands-400.eot create mode 100644 app/webroot/webfonts/fa-brands-400.svg create mode 100644 app/webroot/webfonts/fa-brands-400.ttf create mode 100644 app/webroot/webfonts/fa-brands-400.woff create mode 100644 app/webroot/webfonts/fa-brands-400.woff2 create mode 100644 app/webroot/webfonts/fa-regular-400.eot create mode 100644 app/webroot/webfonts/fa-regular-400.svg create mode 100644 app/webroot/webfonts/fa-regular-400.ttf create mode 100644 app/webroot/webfonts/fa-regular-400.woff create mode 100644 app/webroot/webfonts/fa-regular-400.woff2 create mode 100644 app/webroot/webfonts/fa-solid-900.eot create mode 100644 app/webroot/webfonts/fa-solid-900.svg create mode 100644 app/webroot/webfonts/fa-solid-900.ttf create mode 100644 app/webroot/webfonts/fa-solid-900.woff create mode 100644 app/webroot/webfonts/fa-solid-900.woff2 diff --git a/app/.editorconfig b/app/.editorconfig new file mode 100644 index 0000000..209e731 --- /dev/null +++ b/app/.editorconfig @@ -0,0 +1,23 @@ +; This file is for unifying the coding style for different editors and IDEs. +; More information at http://editorconfig.org + +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.bat] +end_of_line = crlf + +[*.yml] +indent_size = 2 + +[*.twig] +insert_final_newline = false + +[Makefile] +indent_style = tab diff --git a/app/.gitattributes b/app/.gitattributes new file mode 100644 index 0000000..8a2cf52 --- /dev/null +++ b/app/.gitattributes @@ -0,0 +1,54 @@ +# Define the line ending behavior of the different file extensions +# Set default behavior, in case users don't have core.autocrlf set. +* text=auto +* text eol=lf + +# Explicitly declare text files we want to always be normalized and converted +# to native line endings on checkout. +*.php text +*.default text +*.ctp text +*.sql text +*.md text +*.po text +*.js text +*.css text +*.ini text +*.properties text +*.txt text +*.xml text +*.svg text +*.yml text +.htaccess text + +# Declare files that will always have CRLF line endings on checkout. +*.bat eol=crlf + +# Declare files that will always have LF line endings on checkout. +*.pem eol=lf + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary +*.gif binary +*.webp binary +*.ico binary +*.mo binary +*.pdf binary +*.phar binary +*.woff binary +*.woff2 binary +*.ttf binary +*.otf binary +*.eot binary +*.gz binary +*.bz2 binary +*.7z binary +*.zip binary +*.webm binary +*.mp4 binary +*.ogv binary + +# Remove files for archives generated using `git archive` +phpstan.neon export-ignore +.github export-ignore diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..a20bb1f --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,43 @@ +# CakePHP specific files # +########################## +/config/app_local.php +/config/.env +/logs/* +/tmp/* +/vendor/* + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +Icon? +ehthumbs.db +Thumbs.db +.directory + +# Tool specific files # +####################### +# PHPUnit +.phpunit.result.cache +# vim +*~ +*.swp +*.swo +# sublime text & textmate +*.sublime-* +*.stTheme.cache +*.tmlanguage.cache +*.tmPreferences.cache +# Eclipse +.settings/* +# JetBrains, aka PHPStorm, IntelliJ IDEA +.idea/* +# NetBeans +nbproject/* +# Visual Studio Code +.vscode +# Sass preprocessor +.sass-cache/ diff --git a/app/.htaccess b/app/.htaccess new file mode 100644 index 0000000..fc3aac4 --- /dev/null +++ b/app/.htaccess @@ -0,0 +1,5 @@ + + RewriteEngine on + RewriteRule ^$ webroot/ [L] + RewriteRule (.*) webroot/$1 [L] + \ No newline at end of file diff --git a/app/INSTALL/MYSQL.sql b/app/INSTALL/MYSQL.sql new file mode 100644 index 0000000..4fe38ca --- /dev/null +++ b/app/INSTALL/MYSQL.sql @@ -0,0 +1,176 @@ +CREATE TABLE IF NOT EXISTS alignment_tags ( + id int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + alignment_id int(10) UNSIGNED NOT NULL, + tag_id int(10) UNSIGNED NOT NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS alignments ( + id int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + individual_id int(10) UNSIGNED NOT NULL, + organisation_id int(10) UNSIGNED NOT NULL, + type varchar(191) DEFAULT 'member', + PRIMARY KEY (id) +) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS authkeys ( + id int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + authkey varchar(40) CHARSET ascii COLLATE ascii_general_ci, + created int(10) UNSIGNED NOT NULL, + valid_until int(10) UNSIGNED NOT NULL, + user_id int(10) UNSIGNED NOT NULL, + PRIMARY KEY (id), + INDEX (authkey), + INDEX (created), + INDEX (valid_until) +) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; + + +CREATE TABLE IF NOT EXISTS broods ( + id int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + uuid varchar(40) CHARSET ascii COLLATE ascii_general_ci DEFAULT NULL, + name varchar(191) NOT NULL, + url varchar(191) NOT NULL, + description text, + organisation_id int(10) UNSIGNED NOT NULL, + alignment_id int(10) UNSIGNED NOT NULL, + trusted tinyint(1), + pull tinyint(1), + authkey varchar(40) CHARSET ascii COLLATE ascii_general_ci, + PRIMARY KEY (id), + INDEX (uuid), + INDEX (name), + INDEX (url), + INDEX (authkey) +) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; + + +CREATE TABLE IF NOT EXISTS individuals ( + id int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + uuid varchar(40) CHARSET ascii COLLATE ascii_general_ci DEFAULT NULL, + email varchar(191) NOT NULL, + first_name varchar(191) NOT NULL, + last_name varchar(191) NOT NULL, + position text, + PRIMARY KEY (id), + INDEX (uuid), + INDEX (email), + INDEX (first_name), + INDEX (last_name) +) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS individual_encryption_keys ( + id int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + individual_id int(10) UNSIGNED NOT NULL, + encryption_key_id int(10) UNSIGNED NOT NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS encryption_keys ( + id int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + uuid varchar(40) CHARSET ascii COLLATE ascii_general_ci DEFAULT NULL, + type varchar(191) NOT NULL, + encryption_key text, + revoked tinyint(1), + expires int(10) UNSIGNED, + PRIMARY KEY (id), + INDEX (uuid), + INDEX (type), + INDEX (expires) +) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS organisation_encryption_keys ( + id int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + organisation_id int(10) UNSIGNED NOT NULL, + encryption_key_id int(10) UNSIGNED NOT NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; + + +CREATE TABLE IF NOT EXISTS organisations ( + id int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + uuid varchar(40) CHARSET ascii COLLATE ascii_general_ci DEFAULT NULL, + name varchar(191) NOT NULL, + url varchar(191), + nationality varchar(191), + sector varchar(191), + type varchar(191), + contacts text, + PRIMARY KEY (id), + INDEX (uuid), + INDEX (name), + INDEX (url), + INDEX (nationality), + INDEX (sector), + INDEX (type) +) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS roles ( + id int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + uuid varchar(40) CHARSET ascii COLLATE ascii_general_ci DEFAULT NULL, + name varchar(191) NOT NULL, + is_default tinyint(1), + perm_admin tinyint(1), + PRIMARY KEY (id), + INDEX (name), + INDEX (uuid) +) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS tags ( + id int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + name varchar(191) NOT NULL, + description text, + colour varchar(6) CHARSET ascii COLLATE ascii_general_ci NOT NULL, + PRIMARY KEY (id), + INDEX (name) +) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS user_keys ( + id int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + user_id int(10) UNSIGNED NOT NULL, + authkey_id int(10) UNSIGNED NOT NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS users ( + id int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + uuid varchar(40) CHARSET ascii COLLATE ascii_general_ci DEFAULT NULL, + email varchar(191) NOT NULL, + password varchar(191), + role_id int(11) UNSIGNED NOT NULL, + individual_id int(11) UNSIGNED NOT NULL, + PRIMARY KEY (id), + INDEX (uuid), + INDEX (email) +) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; + +ALTER TABLE alignment_tags + ADD FOREIGN KEY (alignment_id) REFERENCES alignments(id), + ADD FOREIGN KEY (tag_id) REFERENCES tags(id); + +ALTER TABLE alignments + ADD FOREIGN KEY (individual_id) REFERENCES individuals(id), + ADD FOREIGN KEY (organisation_id) REFERENCES organisations(id); + +ALTER TABLE authkeys + ADD FOREIGN KEY (user_id) REFERENCES users(id); + +ALTER TABLE broods + ADD FOREIGN KEY (alignment_id) REFERENCES alignments(id); + +ALTER TABLE individual_encryption_keys + ADD FOREIGN KEY (individual_id) REFERENCES individuals(id), + ADD FOREIGN KEY (encryption_key_id) REFERENCES encryption_keys(id); + +ALTER TABLE organisation_encryption_keys + ADD FOREIGN KEY (organisation_id) REFERENCES organisations(id), + ADD FOREIGN KEY (encryption_key_id) REFERENCES encryption_keys(id); + +ALTER TABLE user_keys + ADD FOREIGN KEY (user_id) REFERENCES users(id), + ADD FOREIGN KEY (authkey_id) REFERENCES authkeys(id); + +ALTER TABLE users + ADD FOREIGN KEY (role_id) REFERENCES roles(id), + ADD FOREIGN KEY (individual_id) REFERENCES individuals(id); + diff --git a/app/INSTALL/clean.sql b/app/INSTALL/clean.sql new file mode 100644 index 0000000..40cd9ef --- /dev/null +++ b/app/INSTALL/clean.sql @@ -0,0 +1,14 @@ +SET FOREIGN_KEY_CHECKS=0; +DROP TABLE IF EXISTS alignment_keys; +DROP TABLE IF EXISTS alignments; +DROP TABLE IF EXISTS authkeys; +DROP TABLE IF EXISTS broods; +DROP TABLE IF EXISTS individuals; +DROP TABLE IF EXISTS encryption_keys; +DROP TABLE IF EXISTS organisation_encryption_keys; +DROP TABLE IF EXISTS organisations; +DROP TABLE IF EXISTS roles; +DROP TABLE IF EXISTS tags; +DROP TABLE IF EXISTS user_keys; +DROP TABLE IF EXISTS users; +SET FOREIGN_KEY_CHECKS=1; diff --git a/app/INSTALL/data.sql b/app/INSTALL/data.sql new file mode 100644 index 0000000..7c6bef9 --- /dev/null +++ b/app/INSTALL/data.sql @@ -0,0 +1,6 @@ +INSERT INTO organisations (uuid, name, url, nationality, sector, type, contacts) +VALUES ('11111111-1111-1111-1111-111111111111', 'foo', 'http://google.com', 'NO', '', '', ''); + +INSERT INTO organisations (uuid, name, url, nationality, sector, type, contacts) +VALUES ('11111111-1111-1111-1111-111111111112', 'bar', 'http://bing.com', 'HU', '', '', ''); + diff --git a/app/README.md b/app/README.md new file mode 100644 index 0000000..010b6b0 --- /dev/null +++ b/app/README.md @@ -0,0 +1,53 @@ +# CakePHP Application Skeleton + +[![Build Status](https://img.shields.io/travis/cakephp/app/master.svg?style=flat-square)](https://travis-ci.org/cakephp/app) +[![Total Downloads](https://img.shields.io/packagist/dt/cakephp/app.svg?style=flat-square)](https://packagist.org/packages/cakephp/app) +[![PHPStan](https://img.shields.io/badge/PHPStan-level%207-brightgreen.svg?style=flat-square)](https://github.com/phpstan/phpstan) + +A skeleton for creating applications with [CakePHP](https://cakephp.org) 4.x. + +The framework source code can be found here: [cakephp/cakephp](https://github.com/cakephp/cakephp). + +## Installation + +1. Download [Composer](https://getcomposer.org/doc/00-intro.md) or update `composer self-update`. +2. Run `php composer.phar create-project --prefer-dist cakephp/app [app_name]`. + +If Composer is installed globally, run + +```bash +composer create-project --prefer-dist cakephp/app +``` + +In case you want to use a custom app dir name (e.g. `/myapp/`): + +```bash +composer create-project --prefer-dist cakephp/app myapp +``` + +You can now either use your machine's webserver to view the default home page, or start +up the built-in webserver with: + +```bash +bin/cake server -p 8765 +``` + +Then visit `http://localhost:8765` to see the welcome page. + +## Update + +Since this skeleton is a starting point for your application and various files +would have been modified as per your needs, there isn't a way to provide +automated upgrades, so you have to do any updates manually. + +## Configuration + +Read and edit the environment specific `config/app_local.php` and setup the +`'Datasources'` and any other configuration relevant for your application. +Other environment agnostic settings can be changed in `config/app.php`. + +## Layout + +The app skeleton uses [Milligram](https://milligram.io/) (v1.3) minimalist CSS +framework by default. You can, however, replace it with any other library or +custom styles. diff --git a/app/bin/cake b/app/bin/cake new file mode 100755 index 0000000..4b696c8 --- /dev/null +++ b/app/bin/cake @@ -0,0 +1,75 @@ +#!/usr/bin/env sh +################################################################################ +# +# Cake is a shell script for invoking CakePHP shell commands +# +# CakePHP(tm) : Rapid Development Framework (https://cakephp.org) +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# +# Licensed under The MIT License +# For full copyright and license information, please see the LICENSE.txt +# Redistributions of files must retain the above copyright notice. +# +# @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# @link https://cakephp.org CakePHP(tm) Project +# @since 1.2.0 +# @license https://opensource.org/licenses/mit-license.php MIT License +# +################################################################################ + +# Canonicalize by following every symlink of the given name recursively +canonicalize() { + NAME="$1" + if [ -f "$NAME" ] + then + DIR=$(dirname -- "$NAME") + NAME=$(cd -P "$DIR" > /dev/null && pwd -P)/$(basename -- "$NAME") + fi + while [ -h "$NAME" ]; do + DIR=$(dirname -- "$NAME") + SYM=$(readlink "$NAME") + NAME=$(cd "$DIR" > /dev/null && cd "$(dirname -- "$SYM")" > /dev/null && pwd)/$(basename -- "$SYM") + done + echo "$NAME" +} + +# Find a CLI version of PHP +findCliPhp() { + for TESTEXEC in php php-cli /usr/local/bin/php + do + SAPI=$(echo "" | $TESTEXEC 2>/dev/null) + if [ "$SAPI" = "cli" ] + then + echo $TESTEXEC + return + fi + done + echo "Failed to find a CLI version of PHP; falling back to system standard php executable" >&2 + echo "php"; +} + +# If current path is a symlink, resolve to real path +realname="$0" +if [ -L "$realname" ] +then + realname=$(readlink -f "$0") +fi + +CONSOLE=$(dirname -- "$(canonicalize "$realname")") +APP=$(dirname "$CONSOLE") + +# If your CLI PHP is somewhere that this doesn't find, you can define a PHP environment +# variable with the correct path in it. +if [ -z "$PHP" ] +then + PHP=$(findCliPhp) +fi + +if [ "$(basename "$realname")" != 'cake' ] +then + exec "$PHP" "$CONSOLE"/cake.php "$(basename "$realname")" "$@" +else + exec "$PHP" "$CONSOLE"/cake.php "$@" +fi + +exit diff --git a/app/bin/cake.bat b/app/bin/cake.bat new file mode 100644 index 0000000..ad13782 --- /dev/null +++ b/app/bin/cake.bat @@ -0,0 +1,27 @@ +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: Cake is a Windows batch script for invoking CakePHP shell commands +:: +:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org) +:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +:: +:: Licensed under The MIT License +:: Redistributions of files must retain the above copyright notice. +:: +:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +:: @link https://cakephp.org CakePHP(tm) Project +:: @since 2.0.0 +:: @license https://opensource.org/licenses/mit-license.php MIT License +:: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +@echo off + +SET app=%0 +SET lib=%~dp0 + +php "%lib%cake.php" %* + +echo. + +exit /B %ERRORLEVEL% diff --git a/app/bin/cake.php b/app/bin/cake.php new file mode 100644 index 0000000..320ee36 --- /dev/null +++ b/app/bin/cake.php @@ -0,0 +1,12 @@ +#!/usr/bin/php -q +run($argv)); diff --git a/app/composer.json b/app/composer.json new file mode 100644 index 0000000..2dbfb71 --- /dev/null +++ b/app/composer.json @@ -0,0 +1,56 @@ +{ + "name": "cakephp/app", + "description": "CakePHP skeleton app", + "homepage": "https://cakephp.org", + "type": "project", + "license": "MIT", + "require": { + "php": ">=7.2", + "cakephp/cakephp": "^4.0", + "cakephp/migrations": "^3.0", + "cakephp/plugin-installer": "^1.2", + "mobiledetect/mobiledetectlib": "^2.8" + }, + "require-dev": { + "cakephp/bake": "^2.0.3", + "cakephp/cakephp-codesniffer": "~4.0.0", + "cakephp/debug_kit": "^4.0", + "josegonzalez/dotenv": "^3.2", + "phpunit/phpunit": "^8.5", + "psy/psysh": "@stable" + }, + "suggest": { + "markstory/asset_compress": "An asset compression plugin which provides file concatenation and a flexible filter system for preprocessing and minification.", + "dereuromark/cakephp-ide-helper": "After baking your code, this keeps your annotations in sync with the code evolving from there on for maximum IDE and PHPStan/Psalm compatibility.", + "phpstan/phpstan": "PHPStan focuses on finding errors in your code without actually running it. It catches whole classes of bugs even before you write tests for the code." + }, + "autoload": { + "psr-4": { + "App\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "App\\Test\\": "tests/", + "Cake\\Test\\": "vendor/cakephp/cakephp/tests/" + } + }, + "scripts": { + "post-install-cmd": "App\\Console\\Installer::postInstall", + "post-create-project-cmd": "App\\Console\\Installer::postInstall", + "post-autoload-dump": "Cake\\Composer\\Installer\\PluginInstaller::postAutoloadDump", + "check": [ + "@test", + "@cs-check" + ], + "cs-check": "phpcs --colors -p --standard=vendor/cakephp/cakephp-codesniffer/CakePHP src/ tests/", + "cs-fix": "phpcbf --colors --standard=vendor/cakephp/cakephp-codesniffer/CakePHP src/ tests/", + "stan": "phpstan analyse src/", + "test": "phpunit --colors=always" + }, + "prefer-stable": true, + "config": { + "sort-packages": true + }, + "minimum-stability": "dev" +} diff --git a/app/composer.lock b/app/composer.lock new file mode 100644 index 0000000..d60bd87 --- /dev/null +++ b/app/composer.lock @@ -0,0 +1,4548 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "78f0813d2e19252372610ff0834d4122", + "packages": [ + { + "name": "aura/intl", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/auraphp/Aura.Intl.git", + "reference": "7fce228980b19bf4dee2d7bbd6202a69b0dde926" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/auraphp/Aura.Intl/zipball/7fce228980b19bf4dee2d7bbd6202a69b0dde926", + "reference": "7fce228980b19bf4dee2d7bbd6202a69b0dde926", + "shasum": "" + }, + "require": { + "php": "^5.6|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Aura\\Intl\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aura.Intl Contributors", + "homepage": "https://github.com/auraphp/Aura.Intl/contributors" + } + ], + "description": "The Aura Intl package provides internationalization tools, specifically message translation.", + "homepage": "https://github.com/auraphp/Aura.Intl", + "keywords": [ + "g11n", + "globalization", + "i18n", + "internationalization", + "intl", + "l10n", + "localization" + ], + "time": "2017-01-20T05:00:11+00:00" + }, + { + "name": "cakephp/cakephp", + "version": "4.0.3", + "source": { + "type": "git", + "url": "https://github.com/cakephp/cakephp.git", + "reference": "94435ab211196ce92014a83ec7bab4e385bf8ba3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/cakephp/zipball/94435ab211196ce92014a83ec7bab4e385bf8ba3", + "reference": "94435ab211196ce92014a83ec7bab4e385bf8ba3", + "shasum": "" + }, + "require": { + "aura/intl": "^3.0.0", + "cakephp/chronos": "^2.0", + "composer/ca-bundle": "^1.2", + "ext-intl": "*", + "ext-mbstring": "*", + "laminas/laminas-diactoros": "^2.2.2", + "laminas/laminas-httphandlerrunner": "^1.1", + "php": ">=7.2.0", + "psr/http-client": "^1.0", + "psr/http-server-handler": "^1.0", + "psr/http-server-middleware": "^1.0", + "psr/log": "^1.0.0", + "psr/simple-cache": "^1.0.0" + }, + "replace": { + "cakephp/cache": "self.version", + "cakephp/collection": "self.version", + "cakephp/console": "self.version", + "cakephp/core": "self.version", + "cakephp/database": "self.version", + "cakephp/datasource": "self.version", + "cakephp/event": "self.version", + "cakephp/filesystem": "self.version", + "cakephp/form": "self.version", + "cakephp/http": "self.version", + "cakephp/i18n": "self.version", + "cakephp/log": "self.version", + "cakephp/orm": "self.version", + "cakephp/utility": "self.version", + "cakephp/validation": "self.version" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^4.0", + "mikey179/vfsstream": "^1.6", + "paragonie/csp-builder": "^2.3", + "phpunit/phpunit": "~8.5.0" + }, + "suggest": { + "ext-curl": "To enable more efficient network calls in Http\\Client.", + "ext-openssl": "To use Security::encrypt() or have secure CSRF token generation.", + "lib-ICU": "The intl PHP library, to use Text::transliterate() or Text::slug()", + "paragonie/csp-builder": "CSP builder, to use the CSP Middleware" + }, + "type": "library", + "autoload": { + "psr-4": { + "Cake\\": "src/" + }, + "files": [ + "src/Core/functions.php", + "src/Collection/functions.php", + "src/I18n/functions.php", + "src/Utility/bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/cakephp/graphs/contributors" + } + ], + "description": "The CakePHP framework", + "homepage": "https://cakephp.org", + "keywords": [ + "conventions over configuration", + "dry", + "form", + "framework", + "mvc", + "orm", + "psr-7", + "rapid-development", + "validation" + ], + "time": "2020-01-26T02:19:21+00:00" + }, + { + "name": "cakephp/chronos", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/cakephp/chronos.git", + "reference": "e1044d27cabf12d19097b436001aa96a3c2e4b0a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/chronos/zipball/e1044d27cabf12d19097b436001aa96a3c2e4b0a", + "reference": "e1044d27cabf12d19097b436001aa96a3c2e4b0a", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^4.0", + "phpbench/phpbench": "^1.0@dev", + "phpunit/phpunit": "^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Cake\\Chronos\\": "src/" + }, + "files": [ + "src/carbon_compat.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "http://nesbot.com" + }, + { + "name": "The CakePHP Team", + "homepage": "http://cakephp.org" + } + ], + "description": "A simple API extension for DateTime.", + "homepage": "http://cakephp.org", + "keywords": [ + "date", + "datetime", + "time" + ], + "time": "2020-02-08T02:38:43+00:00" + }, + { + "name": "cakephp/migrations", + "version": "3.0.0-beta2", + "source": { + "type": "git", + "url": "https://github.com/cakephp/migrations.git", + "reference": "4cc2222dbde87fa6827d76ede01e13ce3ff5c78f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/migrations/zipball/4cc2222dbde87fa6827d76ede01e13ce3ff5c78f", + "reference": "4cc2222dbde87fa6827d76ede01e13ce3ff5c78f", + "shasum": "" + }, + "require": { + "cakephp/cache": "^4.0", + "cakephp/orm": "^4.0", + "php": ">=7.2.0", + "robmorgan/phinx": "0.next-dev" + }, + "require-dev": { + "cakephp/bake": "^2.0", + "cakephp/cakephp": "^4.0", + "cakephp/cakephp-codesniffer": "dev-next", + "phpunit/phpunit": "^8.0" + }, + "suggest": { + "cakephp/bake": "Required if you want to generate migrations." + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "Migrations\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/migrations/graphs/contributors" + } + ], + "description": "Database Migration plugin for CakePHP based on Phinx", + "homepage": "https://github.com/cakephp/migrations", + "keywords": [ + "cakephp", + "migrations" + ], + "time": "2019-12-18T08:16:53+00:00" + }, + { + "name": "cakephp/plugin-installer", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/cakephp/plugin-installer.git", + "reference": "3be2ea116603341b196592053e973f4abe71e8b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/plugin-installer/zipball/3be2ea116603341b196592053e973f4abe71e8b2", + "reference": "3be2ea116603341b196592053e973f4abe71e8b2", + "shasum": "" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "dev-master", + "composer/composer": "^1.0", + "phpunit/phpunit": "^4.8|^5.7|^6.0" + }, + "type": "composer-installer", + "extra": { + "class": "Cake\\Composer\\Installer\\PluginInstaller" + }, + "autoload": { + "psr-4": { + "Cake\\Composer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://cakephp.org" + } + ], + "description": "A composer installer for CakePHP 3.0+ plugins.", + "time": "2019-11-12T10:21:19+00:00" + }, + { + "name": "composer/ca-bundle", + "version": "1.2.6", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/47fe531de31fca4a1b997f87308e7d7804348f7e", + "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", + "psr/log": "^1.0", + "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "time": "2020-01-13T10:02:55+00:00" + }, + { + "name": "laminas/laminas-diactoros", + "version": "2.2.2", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-diactoros.git", + "reference": "95178c4751d737cdf9ab0a9f70a42754ac860e7b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/95178c4751d737cdf9ab0a9f70a42754ac860e7b", + "reference": "95178c4751d737cdf9ab0a9f70a42754ac860e7b", + "shasum": "" + }, + "require": { + "laminas/laminas-zendframework-bridge": "^1.0", + "php": "^7.1", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "conflict": { + "phpspec/prophecy": "<1.9.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "replace": { + "zendframework/zend-diactoros": "self.version" + }, + "require-dev": { + "ext-curl": "*", + "ext-dom": "*", + "ext-libxml": "*", + "http-interop/http-factory-tests": "^0.5.0", + "laminas/laminas-coding-standard": "~1.0.0", + "php-http/psr7-integration-tests": "dev-master", + "phpunit/phpunit": "^7.5.18" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev", + "dev-develop": "2.2.x-dev", + "dev-release-1.8": "1.8.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions/create_uploaded_file.php", + "src/functions/marshal_headers_from_sapi.php", + "src/functions/marshal_method_from_sapi.php", + "src/functions/marshal_protocol_version_from_sapi.php", + "src/functions/marshal_uri_from_sapi.php", + "src/functions/normalize_server.php", + "src/functions/normalize_uploaded_files.php", + "src/functions/parse_cookie_header.php", + "src/functions/create_uploaded_file.legacy.php", + "src/functions/marshal_headers_from_sapi.legacy.php", + "src/functions/marshal_method_from_sapi.legacy.php", + "src/functions/marshal_protocol_version_from_sapi.legacy.php", + "src/functions/marshal_uri_from_sapi.legacy.php", + "src/functions/normalize_server.legacy.php", + "src/functions/normalize_uploaded_files.legacy.php", + "src/functions/parse_cookie_header.legacy.php" + ], + "psr-4": { + "Laminas\\Diactoros\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "PSR HTTP Message implementations", + "homepage": "https://laminas.dev", + "keywords": [ + "http", + "laminas", + "psr", + "psr-7" + ], + "time": "2020-01-07T19:39:26+00:00" + }, + { + "name": "laminas/laminas-httphandlerrunner", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-httphandlerrunner.git", + "reference": "296f5ff35074dd981d1570a66b95596c81808087" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-httphandlerrunner/zipball/296f5ff35074dd981d1570a66b95596c81808087", + "reference": "296f5ff35074dd981d1570a66b95596c81808087", + "shasum": "" + }, + "require": { + "laminas/laminas-zendframework-bridge": "^1.0", + "php": "^7.1", + "psr/http-message": "^1.0", + "psr/http-message-implementation": "^1.0", + "psr/http-server-handler": "^1.0" + }, + "replace": { + "zendframework/zend-httphandlerrunner": "self.version" + }, + "require-dev": { + "laminas/laminas-coding-standard": "~1.0.0", + "laminas/laminas-diactoros": "^1.7 || ^2.1.1", + "phpunit/phpunit": "^7.0.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev", + "dev-develop": "1.2.x-dev" + }, + "laminas": { + "config-provider": "Laminas\\HttpHandlerRunner\\ConfigProvider" + } + }, + "autoload": { + "psr-4": { + "Laminas\\HttpHandlerRunner\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Execute PSR-15 RequestHandlerInterface instances and emit responses they generate.", + "homepage": "https://laminas.dev", + "keywords": [ + "components", + "laminas", + "mezzio", + "psr-15", + "psr-7" + ], + "time": "2019-12-31T17:06:16+00:00" + }, + { + "name": "laminas/laminas-zendframework-bridge", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-zendframework-bridge.git", + "reference": "0fb9675b84a1666ab45182b6c5b29956921e818d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/0fb9675b84a1666ab45182b6c5b29956921e818d", + "reference": "0fb9675b84a1666ab45182b6c5b29956921e818d", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev", + "dev-develop": "1.1.x-dev" + }, + "laminas": { + "module": "Laminas\\ZendFrameworkBridge" + } + }, + "autoload": { + "files": [ + "src/autoload.php" + ], + "psr-4": { + "Laminas\\ZendFrameworkBridge\\": "src//" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Alias legacy ZF class names to Laminas Project equivalents.", + "keywords": [ + "ZendFramework", + "autoloading", + "laminas", + "zf" + ], + "time": "2020-01-07T22:58:31+00:00" + }, + { + "name": "mobiledetect/mobiledetectlib", + "version": "2.8.34", + "source": { + "type": "git", + "url": "https://github.com/serbanghita/Mobile-Detect.git", + "reference": "6f8113f57a508494ca36acbcfa2dc2d923c7ed5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/6f8113f57a508494ca36acbcfa2dc2d923c7ed5b", + "reference": "6f8113f57a508494ca36acbcfa2dc2d923c7ed5b", + "shasum": "" + }, + "require": { + "php": ">=5.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8.35||~5.7" + }, + "type": "library", + "autoload": { + "classmap": [ + "Mobile_Detect.php" + ], + "psr-0": { + "Detection": "namespaced/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Serban Ghita", + "email": "serbanghita@gmail.com", + "homepage": "http://mobiledetect.net", + "role": "Developer" + } + ], + "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.", + "homepage": "https://github.com/serbanghita/Mobile-Detect", + "keywords": [ + "detect mobile devices", + "mobile", + "mobile detect", + "mobile detector", + "php mobile detect" + ], + "time": "2019-09-18T18:44:20+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "496a823ef742b632934724bf769560c2a5c7c44e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/496a823ef742b632934724bf769560c2a5c7c44e", + "reference": "496a823ef742b632934724bf769560c2a5c7c44e", + "shasum": "" + }, + "require": { + "php": "^7.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "time": "2018-10-30T23:29:13+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/http-server-handler", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" + ], + "time": "2018-10-30T16:46:14+00:00" + }, + { + "name": "psr/http-server-middleware", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/2296f45510945530b9dceb8bcedb5cb84d40c5f5", + "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0", + "psr/http-server-handler": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side middleware", + "keywords": [ + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" + ], + "time": "2018-10-30T17:12:04+00:00" + }, + { + "name": "psr/log", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2019-11-01T11:05:21+00:00" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "time": "2017-10-23T01:57:42+00:00" + }, + { + "name": "robmorgan/phinx", + "version": "dev-0.next", + "source": { + "type": "git", + "url": "https://github.com/cakephp/phinx.git", + "reference": "7b3ca6c0a97381d391a1ffb4b8a789415cfe8607" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/phinx/zipball/7b3ca6c0a97381d391a1ffb4b8a789415cfe8607", + "reference": "7b3ca6c0a97381d391a1ffb4b8a789415cfe8607", + "shasum": "" + }, + "require": { + "cakephp/collection": "^4.0", + "cakephp/database": "^4.0", + "php": ">=7.2", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^3.0", + "phpunit/phpunit": "^8.5", + "sebastian/comparator": ">=1.2.3" + }, + "bin": [ + "bin/phinx" + ], + "type": "library", + "autoload": { + "psr-4": { + "Phinx\\": "src/Phinx/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Rob Morgan", + "email": "robbym@gmail.com", + "homepage": "https://robmorgan.id.au", + "role": "Lead Developer" + }, + { + "name": "Woody Gilk", + "email": "woody.gilk@gmail.com", + "homepage": "https://shadowhand.me", + "role": "Developer" + }, + { + "name": "Richard Quadling", + "email": "rquadling@gmail.com", + "role": "Developer" + }, + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/phinx/graphs/contributors", + "role": "Developer" + } + ], + "description": "Phinx makes it ridiculously easy to manage the database migrations for your PHP app.", + "homepage": "https://phinx.org", + "keywords": [ + "database", + "database migrations", + "db", + "migrations", + "phinx" + ], + "time": "2020-01-03T23:12:36+00:00" + }, + { + "name": "symfony/config", + "version": "v5.0.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "7640c6704f56bf64045066bc5d93fd9d664baa63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/7640c6704f56bf64045066bc5d93fd9d664baa63", + "reference": "7640c6704f56bf64045066bc5d93fd9d664baa63", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/filesystem": "^4.4|^5.0", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<4.4" + }, + "require-dev": { + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^4.4|^5.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Config Component", + "homepage": "https://symfony.com", + "time": "2020-01-04T14:08:26+00:00" + }, + { + "name": "symfony/console", + "version": "v5.0.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "91c294166c38d8c0858a86fad76d8c14dc1144c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/91c294166c38d8c0858a86fad76d8c14dc1144c8", + "reference": "91c294166c38d8c0858a86fad76d8c14dc1144c8", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/dependency-injection": "<4.4", + "symfony/event-dispatcher": "<4.4", + "symfony/lock": "<4.4", + "symfony/process": "<4.4" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2020-01-25T15:56:29+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v5.0.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "3afadc0f57cd74f86379d073e694b0f2cda2a88c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/3afadc0f57cd74f86379d073e694b0f2cda2a88c", + "reference": "3afadc0f57cd74f86379d073e694b0f2cda2a88c", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "time": "2020-01-21T08:40:24+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.14.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", + "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.14-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2020-01-13T11:15:53+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.14.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/34094cfa9abe1f0f14f48f490772db7a775559f2", + "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.14-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2020-01-13T11:15:53+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.14.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/5e66a0fa1070bf46bec4bea7962d285108edd675", + "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.14-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2020-01-13T11:15:53+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "144c5e51266b281231e947b51223ba14acf1a749" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749", + "reference": "144c5e51266b281231e947b51223ba14acf1a749", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-11-18T17:27:11+00:00" + }, + { + "name": "symfony/yaml", + "version": "v5.0.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "69b44e3b8f90949aee2eb3aa9b86ceeb01cbf62a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/69b44e3b8f90949aee2eb3aa9b86ceeb01cbf62a", + "reference": "69b44e3b8f90949aee2eb3aa9b86ceeb01cbf62a", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<4.4" + }, + "require-dev": { + "symfony/console": "^4.4|^5.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2020-01-21T11:12:28+00:00" + } + ], + "packages-dev": [ + { + "name": "cakephp/bake", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/cakephp/bake.git", + "reference": "113502b5687026adf158fde3132354f4dcd49ed4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/bake/zipball/113502b5687026adf158fde3132354f4dcd49ed4", + "reference": "113502b5687026adf158fde3132354f4dcd49ed4", + "shasum": "" + }, + "require": { + "cakephp/cakephp": "^4.0", + "cakephp/plugin-installer": "^1.0", + "php": ">=7.2", + "wyrihaximus/twig-view": "^5.0.1" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^4.0", + "phpunit/phpunit": "~8.5.0" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "Bake\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/bake/graphs/contributors" + } + ], + "description": "Bake plugin for CakePHP", + "homepage": "https://github.com/cakephp/bake", + "keywords": [ + "bake", + "cakephp" + ], + "time": "2020-01-06T15:41:13+00:00" + }, + { + "name": "cakephp/cakephp-codesniffer", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/cakephp/cakephp-codesniffer.git", + "reference": "637e424134e6fc7c6c3ecddd750ef743eb7869fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/cakephp-codesniffer/zipball/637e424134e6fc7c6c3ecddd750ef743eb7869fc", + "reference": "637e424134e6fc7c6c3ecddd750ef743eb7869fc", + "shasum": "" + }, + "require": { + "php": "^7.1", + "slevomat/coding-standard": "^6.0", + "squizlabs/php_codesniffer": "~3.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "CakePHP\\": "CakePHP/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/cakephp-codesniffer/graphs/contributors" + } + ], + "description": "CakePHP CodeSniffer Standards", + "homepage": "https://cakephp.org", + "keywords": [ + "codesniffer", + "framework" + ], + "time": "2020-01-13T22:00:38+00:00" + }, + { + "name": "cakephp/debug_kit", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/cakephp/debug_kit.git", + "reference": "56805287711dc81c081865250faeee80ce5eec50" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/debug_kit/zipball/56805287711dc81c081865250faeee80ce5eec50", + "reference": "56805287711dc81c081865250faeee80ce5eec50", + "shasum": "" + }, + "require": { + "cakephp/cakephp": "^4.0", + "cakephp/chronos": "^2.0", + "cakephp/plugin-installer": "^1.0", + "composer/composer": "^1.3", + "jdorn/sql-formatter": "^1.2", + "php": ">=7.2" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^4.0", + "phpunit/phpunit": "^8.0" + }, + "suggest": { + "ext-pdo_sqlite": "DebugKit needs to store panel data in a database. SQLite is simple and easy to use." + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "DebugKit\\": "src/", + "DebugKit\\Test\\Fixture\\": "tests/Fixture/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Story", + "homepage": "https://mark-story.com", + "role": "Author" + }, + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/debug_kit/graphs/contributors" + } + ], + "description": "CakePHP Debug Kit", + "homepage": "https://github.com/cakephp/debug_kit", + "keywords": [ + "cakephp", + "debug", + "kit" + ], + "time": "2020-01-16T14:50:30+00:00" + }, + { + "name": "composer/composer", + "version": "1.10.0-RC", + "source": { + "type": "git", + "url": "https://github.com/composer/composer.git", + "reference": "ec39b4cbb5e012365d70cd95969ea11780d3c1fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/composer/zipball/ec39b4cbb5e012365d70cd95969ea11780d3c1fc", + "reference": "ec39b4cbb5e012365d70cd95969ea11780d3c1fc", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.0", + "composer/semver": "^1.0", + "composer/spdx-licenses": "^1.2", + "composer/xdebug-handler": "^1.1", + "justinrainbow/json-schema": "^3.0 || ^4.0 || ^5.0", + "php": "^5.3.2 || ^7.0", + "psr/log": "^1.0", + "seld/jsonlint": "^1.4", + "seld/phar-utils": "^1.0", + "symfony/console": "^2.7 || ^3.0 || ^4.0 || ^5.0", + "symfony/filesystem": "^2.7 || ^3.0 || ^4.0 || ^5.0", + "symfony/finder": "^2.7 || ^3.0 || ^4.0 || ^5.0", + "symfony/process": "^2.7 || ^3.0 || ^4.0 || ^5.0" + }, + "conflict": { + "symfony/console": "2.8.38" + }, + "require-dev": { + "phpspec/prophecy": "^1.10", + "symfony/phpunit-bridge": "^3.4" + }, + "suggest": { + "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", + "ext-zip": "Enabling the zip extension allows you to unzip archives", + "ext-zlib": "Allow gzip compression of HTTP requests" + }, + "bin": [ + "bin/composer" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\": "src/Composer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.", + "homepage": "https://getcomposer.org/", + "keywords": [ + "autoload", + "dependency", + "package" + ], + "time": "2020-02-14T14:11:30+00:00" + }, + { + "name": "composer/semver", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de", + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.5 || ^5.0.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "time": "2020-01-13T12:06:48+00:00" + }, + { + "name": "composer/spdx-licenses", + "version": "1.5.3", + "source": { + "type": "git", + "url": "https://github.com/composer/spdx-licenses.git", + "reference": "0c3e51e1880ca149682332770e25977c70cf9dae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/0c3e51e1880ca149682332770e25977c70cf9dae", + "reference": "0c3e51e1880ca149682332770e25977c70cf9dae", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Spdx\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "SPDX licenses list and validation library.", + "keywords": [ + "license", + "spdx", + "validator" + ], + "time": "2020-02-14T07:44:31+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "cbe23383749496fe0f373345208b79568e4bc248" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/cbe23383749496fe0f373345208b79568e4bc248", + "reference": "cbe23383749496fe0f373345208b79568e4bc248", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0", + "psr/log": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "time": "2019-11-06T16:40:04+00:00" + }, + { + "name": "dnoegel/php-xdg-base-dir", + "version": "v0.1.1", + "source": { + "type": "git", + "url": "https://github.com/dnoegel/php-xdg-base-dir.git", + "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", + "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "XdgBaseDir\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "implementation of xdg base directory specification for php", + "time": "2019-12-04T15:06:13+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.13", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-shim": "^0.11", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2019-10-21T16:45:58+00:00" + }, + { + "name": "jakub-onderka/php-console-color", + "version": "v0.2", + "source": { + "type": "git", + "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", + "reference": "d5deaecff52a0d61ccb613bb3804088da0307191" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/d5deaecff52a0d61ccb613bb3804088da0307191", + "reference": "d5deaecff52a0d61ccb613bb3804088da0307191", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "jakub-onderka/php-code-style": "1.0", + "jakub-onderka/php-parallel-lint": "1.0", + "jakub-onderka/php-var-dump-check": "0.*", + "phpunit/phpunit": "~4.3", + "squizlabs/php_codesniffer": "1.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "JakubOnderka\\PhpConsoleColor\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "jakub.onderka@gmail.com" + } + ], + "time": "2018-09-29T17:23:10+00:00" + }, + { + "name": "jakub-onderka/php-console-highlighter", + "version": "v0.4", + "source": { + "type": "git", + "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", + "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/9f7a229a69d52506914b4bc61bfdb199d90c5547", + "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "jakub-onderka/php-console-color": "~0.2", + "php": ">=5.4.0" + }, + "require-dev": { + "jakub-onderka/php-code-style": "~1.0", + "jakub-onderka/php-parallel-lint": "~1.0", + "jakub-onderka/php-var-dump-check": "~0.1", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "JakubOnderka\\PhpConsoleHighlighter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "acci@acci.cz", + "homepage": "http://www.acci.cz/" + } + ], + "description": "Highlight PHP code in terminal", + "time": "2018-09-29T18:48:56+00:00" + }, + { + "name": "jasny/twig-extensions", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/jasny/twig-extensions.git", + "reference": "a694eb02f6fc14ff8e2fceb8b80882c0c926102b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jasny/twig-extensions/zipball/a694eb02f6fc14ff8e2fceb8b80882c0c926102b", + "reference": "a694eb02f6fc14ff8e2fceb8b80882c0c926102b", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "twig/twig": "^2.0 | ^3.0" + }, + "require-dev": { + "ext-intl": "*", + "ext-pcre": "*", + "jasny/php-code-quality": "^2.5", + "php": ">=7.2.0" + }, + "suggest": { + "ext-intl": "Required for the use of the LocalDate Twig extension", + "ext-pcre": "Required for the use of the PCRE Twig extension" + }, + "type": "library", + "autoload": { + "psr-4": { + "Jasny\\Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Arnold Daniels", + "email": "arnold@jasny.net", + "homepage": "http://www.jasny.net" + } + ], + "description": "A set of useful Twig filters", + "homepage": "http://github.com/jasny/twig-extensions#README", + "keywords": [ + "PCRE", + "array", + "date", + "datetime", + "preg", + "regex", + "templating", + "text", + "time" + ], + "time": "2019-12-10T16:04:23+00:00" + }, + { + "name": "jdorn/sql-formatter", + "version": "v1.2.17", + "source": { + "type": "git", + "url": "https://github.com/jdorn/sql-formatter.git", + "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jdorn/sql-formatter/zipball/64990d96e0959dff8e059dfcdc1af130728d92bc", + "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc", + "shasum": "" + }, + "require": { + "php": ">=5.2.4" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "lib" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Dorn", + "email": "jeremy@jeremydorn.com", + "homepage": "http://jeremydorn.com/" + } + ], + "description": "a PHP SQL highlighting library", + "homepage": "https://github.com/jdorn/sql-formatter/", + "keywords": [ + "highlight", + "sql" + ], + "time": "2014-01-12T16:20:24+00:00" + }, + { + "name": "josegonzalez/dotenv", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/josegonzalez/php-dotenv.git", + "reference": "f19174d9d7213a6c20e8e5e268aa7dd042d821ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/josegonzalez/php-dotenv/zipball/f19174d9d7213a6c20e8e5e268aa7dd042d821ca", + "reference": "f19174d9d7213a6c20e8e5e268aa7dd042d821ca", + "shasum": "" + }, + "require": { + "m1/env": "2.*", + "php": ">=5.5.0" + }, + "require-dev": { + "php-mock/php-mock-phpunit": "^1.1", + "satooshi/php-coveralls": "1.*", + "squizlabs/php_codesniffer": "2.*" + }, + "type": "library", + "autoload": { + "psr-0": { + "josegonzalez\\Dotenv": [ + "src", + "tests" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jose Diaz-Gonzalez", + "email": "dotenv@josegonzalez.com", + "homepage": "http://josediazgonzalez.com", + "role": "Maintainer" + } + ], + "description": "dotenv file parsing for PHP", + "homepage": "https://github.com/josegonzalez/php-dotenv", + "keywords": [ + "configuration", + "dotenv", + "php" + ], + "time": "2017-09-19T15:49:58+00:00" + }, + { + "name": "justinrainbow/json-schema", + "version": "5.2.9", + "source": { + "type": "git", + "url": "https://github.com/justinrainbow/json-schema.git", + "reference": "44c6787311242a979fa15c704327c20e7221a0e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/44c6787311242a979fa15c704327c20e7221a0e4", + "reference": "44c6787311242a979fa15c704327c20e7221a0e4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "json-schema/json-schema-test-suite": "1.2.0", + "phpunit/phpunit": "^4.8.35" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert Schönthal", + "email": "seroscho@googlemail.com" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "time": "2019-09-25T14:49:45+00:00" + }, + { + "name": "m1/env", + "version": "2.1.2", + "source": { + "type": "git", + "url": "https://github.com/m1/Env.git", + "reference": "294addeedf15e1149eeb96ec829f2029d2017d39" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/m1/Env/zipball/294addeedf15e1149eeb96ec829f2029d2017d39", + "reference": "294addeedf15e1149eeb96ec829f2029d2017d39", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*", + "scrutinizer/ocular": "~1.1", + "squizlabs/php_codesniffer": "^2.3" + }, + "suggest": { + "josegonzalez/dotenv": "For loading of .env", + "m1/vars": "For loading of configs" + }, + "type": "library", + "autoload": { + "psr-4": { + "M1\\Env\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Miles Croxford", + "email": "hello@milescroxford.com", + "homepage": "http://milescroxford.com", + "role": "Developer" + } + ], + "description": "Env is a lightweight library bringing .env file parser compatibility to PHP. In short - it enables you to read .env files with PHP.", + "homepage": "https://github.com/m1/Env", + "keywords": [ + ".env", + "config", + "dotenv", + "env", + "loader", + "m1", + "parser", + "support" + ], + "time": "2018-06-19T18:55:08+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.9.5", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/b2c28789e80a97badd14145fda39b545d83ca3ef", + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2020-01-17T21:11:47+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.3.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/9a9981c347c5c49d6dfe5cf826bb882b824080dc", + "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "0.0.5", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "time": "2019-11-08T13:50:10+00:00" + }, + { + "name": "phar-io/manifest", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^2.0", + "php": "^5.6 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "time": "2018-07-08T19:23:20+00:00" + }, + { + "name": "phar-io/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "time": "2018-07-08T19:19:57+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "~6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2018-08-07T13:53:10+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "a48807183a4b819072f26e347bbd0b5199a9d15f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/a48807183a4b819072f26e347bbd0b5199a9d15f", + "reference": "a48807183a4b819072f26e347bbd0b5199a9d15f", + "shasum": "" + }, + "require": { + "ext-filter": "^7.1", + "php": "^7.2", + "phpdocumentor/reflection-common": "^2.0", + "phpdocumentor/type-resolver": "^1.0", + "webmozart/assert": "^1" + }, + "require-dev": { + "doctrine/instantiator": "^1", + "mockery/mockery": "^1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2020-02-09T09:16:15+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "shasum": "" + }, + "require": { + "php": "^7.1", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "^7.1", + "mockery/mockery": "~1", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "time": "2019-08-22T18:11:29+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.10.2", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b4400efc9d206e83138e2bb97ed7f5b14b831cd9", + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", + "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5 || ^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2020-01-20T15:57:02+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "0.4.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "928179efc5368145a8b03cb20d58cb3f3136afae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/928179efc5368145a8b03cb20d58cb3f3136afae", + "reference": "928179efc5368145a8b03cb20d58cb3f3136afae", + "shasum": "" + }, + "require": { + "php": "~7.1" + }, + "require-dev": { + "consistence/coding-standard": "^3.5", + "ergebnis/composer-normalize": "^2.0.2", + "jakub-onderka/php-parallel-lint": "^0.9.2", + "phing/phing": "^2.16.0", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^6.3", + "slevomat/coding-standard": "^4.7.2", + "symfony/process": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.4-dev" + } + }, + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "time": "2020-01-25T20:42:48+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "7.0.10", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f1884187926fbb755a9aaf0b3836ad3165b478bf", + "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.2", + "phpunit/php-file-iterator": "^2.0.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^3.1.1", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^4.2.2", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1.3" + }, + "require-dev": { + "phpunit/phpunit": "^8.2.2" + }, + "suggest": { + "ext-xdebug": "^2.7.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2019-11-20T13:55:58+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "050bedf145a257b1ff02746c31894800e5122946" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", + "reference": "050bedf145a257b1ff02746c31894800e5122946", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2018-09-13T20:33:42+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "2.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2019-06-07T04:22:29+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2019-09-17T06:23:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "8.5.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/018b6ac3c8ab20916db85fa91bf6465acb64d1e0", + "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.2.0", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.9.1", + "phar-io/manifest": "^1.0.3", + "phar-io/version": "^2.0.1", + "php": "^7.2", + "phpspec/prophecy": "^1.8.1", + "phpunit/php-code-coverage": "^7.0.7", + "phpunit/php-file-iterator": "^2.0.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^2.1.2", + "sebastian/comparator": "^3.0.2", + "sebastian/diff": "^3.0.2", + "sebastian/environment": "^4.2.2", + "sebastian/exporter": "^3.1.1", + "sebastian/global-state": "^3.0.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^2.0.1", + "sebastian/type": "^1.1.3", + "sebastian/version": "^2.0.1" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*", + "phpunit/php-invoker": "^2.0.0" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.5-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2020-01-08T08:49:49+00:00" + }, + { + "name": "psy/psysh", + "version": "v0.9.12", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "90da7f37568aee36b116a030c5f99c915267edd4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/90da7f37568aee36b116a030c5f99c915267edd4", + "reference": "90da7f37568aee36b116a030c5f99c915267edd4", + "shasum": "" + }, + "require": { + "dnoegel/php-xdg-base-dir": "0.1.*", + "ext-json": "*", + "ext-tokenizer": "*", + "jakub-onderka/php-console-highlighter": "0.3.*|0.4.*", + "nikic/php-parser": "~1.3|~2.0|~3.0|~4.0", + "php": ">=5.4.0", + "symfony/console": "~2.3.10|^2.4.2|~3.0|~4.0|~5.0", + "symfony/var-dumper": "~2.7|~3.0|~4.0|~5.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2", + "hoa/console": "~2.15|~3.16", + "phpunit/phpunit": "~4.8.35|~5.0|~6.0|~7.0" + }, + "suggest": { + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "ext-pdo-sqlite": "The doc command requires SQLite to work.", + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", + "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history.", + "hoa/console": "A pure PHP readline implementation. You'll want this if your PHP install doesn't already support readline or libedit." + }, + "bin": [ + "bin/psysh" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "0.9.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Psy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "http://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "time": "2019-12-06T14:19:43+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2017-03-04T06:30:41+00:00" + }, + { + "name": "sebastian/comparator", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "shasum": "" + }, + "require": { + "php": "^7.1", + "sebastian/diff": "^3.0", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2018-07-12T15:12:46+00:00" + }, + { + "name": "sebastian/diff", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "time": "2019-02-04T06:01:07+00:00" + }, + { + "name": "sebastian/environment", + "version": "4.2.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368", + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.5" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2019-11-20T08:46:58+00:00" + }, + { + "name": "sebastian/exporter", + "version": "3.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2019-09-14T09:02:43+00:00" + }, + { + "name": "sebastian/global-state", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", + "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", + "shasum": "" + }, + "require": { + "php": "^7.2", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^8.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2019-02-01T05:30:01+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2017-08-03T12:35:26+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "773f97c67f28de00d397be301821b06708fca0be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", + "reference": "773f97c67f28de00d397be301821b06708fca0be", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "time": "2017-03-29T09:07:27+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2017-03-03T06:23:57+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2018-10-04T04:07:39+00:00" + }, + { + "name": "sebastian/type", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/3aaaa15fa71d27650d62a948be022fe3b48541a3", + "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3", + "shasum": "" + }, + "require": { + "php": "^7.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "time": "2019-07-02T08:10:15+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "seld/jsonlint", + "version": "1.7.2", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/jsonlint.git", + "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/e2e5d290e4d2a4f0eb449f510071392e00e10d19", + "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "bin": [ + "bin/jsonlint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Seld\\JsonLint\\": "src/Seld/JsonLint/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "JSON Linter", + "keywords": [ + "json", + "linter", + "parser", + "validator" + ], + "time": "2019-10-24T14:27:39+00:00" + }, + { + "name": "seld/phar-utils", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/phar-utils.git", + "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/8800503d56b9867d43d9c303b9cbcc26016e82f0", + "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\PharUtils\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "PHAR file format utilities, for when PHP phars you up", + "keywords": [ + "phar" + ], + "time": "2020-02-14T15:25:33+00:00" + }, + { + "name": "slevomat/coding-standard", + "version": "6.1.5", + "source": { + "type": "git", + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "d767b5e302ff096327466c97fec3cb57f6d16086" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/d767b5e302ff096327466c97fec3cb57f6d16086", + "reference": "d767b5e302ff096327466c97fec3cb57f6d16086", + "shasum": "" + }, + "require": { + "php": "^7.1", + "phpstan/phpdoc-parser": "0.3.5 - 0.4.3", + "squizlabs/php_codesniffer": "^3.5.4" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "0.6.2", + "grogy/php-parallel-lint": "1.1.0", + "phing/phing": "2.16.3", + "phpstan/phpstan": "0.11.19|0.12.9", + "phpstan/phpstan-phpunit": "0.11.2|0.12.6", + "phpstan/phpstan-strict-rules": "0.11.1|0.12.2", + "phpunit/phpunit": "7.5.18|8.5.2" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "SlevomatCodingStandard\\": "SlevomatCodingStandard" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "time": "2020-02-05T21:17:34+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.5.4", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "dceec07328401de6211037abbb18bda423677e26" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dceec07328401de6211037abbb18bda423677e26", + "reference": "dceec07328401de6211037abbb18bda423677e26", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards" + ], + "time": "2020-01-30T22:20:29+00:00" + }, + { + "name": "symfony/finder", + "version": "v5.0.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "4176e7cb846fe08f32518b7e0ed8462e2db8d9bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/4176e7cb846fe08f32518b7e0ed8462e2db8d9bb", + "reference": "4176e7cb846fe08f32518b7e0ed8462e2db8d9bb", + "shasum": "" + }, + "require": { + "php": "^7.2.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "time": "2020-01-04T14:08:26+00:00" + }, + { + "name": "symfony/process", + "version": "v5.0.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "f9ffd870f5ac01abec7b2b5e15f904ca9400ecd1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/f9ffd870f5ac01abec7b2b5e15f904ca9400ecd1", + "reference": "f9ffd870f5ac01abec7b2b5e15f904ca9400ecd1", + "shasum": "" + }, + "require": { + "php": "^7.2.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com", + "time": "2020-01-09T09:53:06+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v5.0.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "923591cfb78a935f0c98968fedfad05bfda9d01f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/923591cfb78a935f0c98968fedfad05bfda9d01f", + "reference": "923591cfb78a935f0c98968fedfad05bfda9d01f", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "phpunit/phpunit": "<5.4.3", + "symfony/console": "<4.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^2.4|^3.0" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony mechanism for exploring and dumping PHP variables", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "time": "2020-01-25T15:56:29+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "time": "2019-06-13T22:48:21+00:00" + }, + { + "name": "twig/markdown-extra", + "version": "v3.0.3", + "source": { + "type": "git", + "url": "https://github.com/twigphp/markdown-extra.git", + "reference": "c9d09a12024febcb6976886794d095a31f1ce6fa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/markdown-extra/zipball/c9d09a12024febcb6976886794d095a31f1ce6fa", + "reference": "c9d09a12024febcb6976886794d095a31f1ce6fa", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "twig/twig": "^2.4|^3.0" + }, + "require-dev": { + "erusev/parsedown": "^1.7", + "league/commonmark": "^1.0", + "league/html-to-markdown": "^4.8", + "michelf/php-markdown": "^1.8", + "symfony/phpunit-bridge": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Twig\\Extra\\Markdown\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "A Twig extension for Markdown", + "homepage": "https://twig.symfony.com", + "keywords": [ + "html", + "markdown", + "twig" + ], + "time": "2020-01-01T17:11:09+00:00" + }, + { + "name": "twig/twig", + "version": "v3.0.3", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "3b88ccd180a6b61ebb517aea3b1a8906762a1dc2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/3b88ccd180a6b61ebb517aea3b1a8906762a1dc2", + "reference": "3b88ccd180a6b61ebb517aea3b1a8906762a1dc2", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3" + }, + "require-dev": { + "psr/container": "^1.0", + "symfony/phpunit-bridge": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "time": "2020-02-11T15:33:47+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "aed98a490f9a8f78468232db345ab9cf606cf598" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/aed98a490f9a8f78468232db345ab9cf606cf598", + "reference": "aed98a490f9a8f78468232db345ab9cf606cf598", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "vimeo/psalm": "<3.6.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36 || ^7.5.13" + }, + "type": "library", + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2020-02-14T12:15:55+00:00" + }, + { + "name": "wyrihaximus/twig-view", + "version": "5.0.1", + "source": { + "type": "git", + "url": "https://github.com/WyriHaximus/TwigView.git", + "reference": "ec1d3091d56a0da9b1756692fa0bf99846a4eb20" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/WyriHaximus/TwigView/zipball/ec1d3091d56a0da9b1756692fa0bf99846a4eb20", + "reference": "ec1d3091d56a0da9b1756692fa0bf99846a4eb20", + "shasum": "" + }, + "require": { + "cakephp/cakephp": "^4.0", + "jasny/twig-extensions": "^1.3", + "php": "^7.2", + "twig/markdown-extra": "^3.0", + "twig/twig": "^3.0" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^4.0", + "cakephp/debug_kit": "^4.0", + "jakub-onderka/php-console-highlighter": "^0.4.0", + "jakub-onderka/php-parallel-lint": "^1.0", + "phpunit/phpunit": "^8.0", + "wyrihaximus/phpunit-class-reflection-helpers": "dev-master" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "WyriHaximus\\TwigView\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Cees-Jan Kiewiet", + "email": "ceesjank@gmail.com", + "homepage": "http://wyrihaximus.net/" + } + ], + "description": "Twig powered View for CakePHP", + "keywords": [ + "cakephp", + "template", + "twig", + "twig2", + "view" + ], + "time": "2019-12-30T11:29:47+00:00" + } + ], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": { + "psy/psysh": 0 + }, + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": ">=7.2" + }, + "platform-dev": [] +} diff --git a/app/config/.env.example b/app/config/.env.example new file mode 100644 index 0000000..15060f7 --- /dev/null +++ b/app/config/.env.example @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Used as a default to seed config/.env which +# enables you to use environment variables to configure +# the aspects of your application that vary by +# environment. +# +# Having this file in production is considered a **SECURITY RISK** and also decreases +# the boostrap performance of your application. +# +# To use this file, first copy it into `config/.env`. Also ensure the related +# code block for loading this file is uncommented in `config/boostrap.php` +# +# In development .env files are parsed by PHP +# and set into the environment. This provides a simpler +# development workflow over standard environment variables. +export APP_NAME="__APP_NAME__" +export DEBUG="true" +export APP_ENCODING="UTF-8" +export APP_DEFAULT_LOCALE="en_US" +export APP_DEFAULT_TIMEZONE="UTC" +export SECURITY_SALT="__SALT__" + +# Uncomment these to define cache configuration via environment variables. +#export CACHE_DURATION="+2 minutes" +#export CACHE_DEFAULT_URL="file://tmp/cache/?prefix=${APP_NAME}_default&duration=${CACHE_DURATION}" +#export CACHE_CAKECORE_URL="file://tmp/cache/persistent?prefix=${APP_NAME}_cake_core&serialize=true&duration=${CACHE_DURATION}" +#export CACHE_CAKEMODEL_URL="file://tmp/cache/models?prefix=${APP_NAME}_cake_model&serialize=true&duration=${CACHE_DURATION}" + +# Uncomment these to define email transport configuration via environment variables. +#export EMAIL_TRANSPORT_DEFAULT_URL="" + +# Uncomment these to define database configuration via environment variables. +#export DATABASE_URL="mysql://my_app:secret@localhost/${APP_NAME}?encoding=utf8&timezone=UTC&cacheMetadata=true"eIdentifiers=false&persistent=false" +#export DATABASE_TEST_URL="mysql://my_app:secret@localhost/test_${APP_NAME}?encoding=utf8&timezone=UTC&cacheMetadata=true"eIdentifiers=false&persistent=false" + +# Uncomment these to define logging configuration via environment variables. +#export LOG_DEBUG_URL="file://logs/?levels[]=notice&levels[]=info&levels[]=debug&file=debug" +#export LOG_ERROR_URL="file://logs/?levels[]=warning&levels[]=error&levels[]=critical&levels[]=alert&levels[]=emergency&file=error" diff --git a/app/config/app.php b/app/config/app.php new file mode 100644 index 0000000..d91d49f --- /dev/null +++ b/app/config/app.php @@ -0,0 +1,401 @@ + filter_var(env('DEBUG', true), FILTER_VALIDATE_BOOLEAN), + + /* + * Configure basic information about the application. + * + * - namespace - The namespace to find app classes under. + * - defaultLocale - The default locale for translation, formatting currencies and numbers, date and time. + * - encoding - The encoding used for HTML + database connections. + * - base - The base directory the app resides in. If false this + * will be auto detected. + * - dir - Name of app directory. + * - webroot - The webroot directory. + * - wwwRoot - The file path to webroot. + * - baseUrl - To configure CakePHP to *not* use mod_rewrite and to + * use CakePHP pretty URLs, remove these .htaccess + * files: + * /.htaccess + * /webroot/.htaccess + * And uncomment the baseUrl key below. + * - fullBaseUrl - A base URL to use for absolute links. When set to false (default) + * CakePHP generates required value based on `HTTP_HOST` environment variable. + * However, you can define it manually to optimize performance or if you + * are concerned about people manipulating the `Host` header. + * - imageBaseUrl - Web path to the public images directory under webroot. + * - cssBaseUrl - Web path to the public css directory under webroot. + * - jsBaseUrl - Web path to the public js directory under webroot. + * - paths - Configure paths for non class based resources. Supports the + * `plugins`, `templates`, `locales` subkeys, which allow the definition of + * paths for plugins, view templates and locale files respectively. + */ + 'App' => [ + 'namespace' => 'App', + 'encoding' => env('APP_ENCODING', 'UTF-8'), + 'defaultLocale' => env('APP_DEFAULT_LOCALE', 'en_US'), + 'defaultTimezone' => env('APP_DEFAULT_TIMEZONE', 'UTC'), + 'base' => false, + 'dir' => 'src', + 'webroot' => 'webroot', + 'wwwRoot' => WWW_ROOT, + //'baseUrl' => env('SCRIPT_NAME'), + 'fullBaseUrl' => false, + 'imageBaseUrl' => 'img/', + 'cssBaseUrl' => 'css/', + 'jsBaseUrl' => 'js/', + 'paths' => [ + 'plugins' => [ROOT . DS . 'plugins' . DS], + 'templates' => [ROOT . DS . 'templates' . DS], + 'locales' => [RESOURCES . 'locales' . DS], + ], + ], + + /* + * Security and encryption configuration + * + * - salt - A random string used in security hashing methods. + * The salt value is also used as the encryption key. + * You should treat it as extremely sensitive data. + */ + 'Security' => [ + 'salt' => env('SECURITY_SALT'), + ], + + /* + * Apply timestamps with the last modified time to static assets (js, css, images). + * Will append a querystring parameter containing the time the file was modified. + * This is useful for busting browser caches. + * + * Set to true to apply timestamps when debug is true. Set to 'force' to always + * enable timestamping regardless of debug value. + */ + 'Asset' => [ + //'timestamp' => true, + // 'cacheTime' => '+1 year' + ], + + /* + * Configure the cache adapters. + */ + 'Cache' => [ + 'default' => [ + 'className' => FileEngine::class, + 'path' => CACHE, + 'url' => env('CACHE_DEFAULT_URL', null), + ], + + /* + * Configure the cache used for general framework caching. + * Translation cache files are stored with this configuration. + * Duration will be set to '+2 minutes' in bootstrap.php when debug = true + * If you set 'className' => 'Null' core cache will be disabled. + */ + '_cake_core_' => [ + 'className' => FileEngine::class, + 'prefix' => 'myapp_cake_core_', + 'path' => CACHE . 'persistent' . DS, + 'serialize' => true, + 'duration' => '+1 years', + 'url' => env('CACHE_CAKECORE_URL', null), + ], + + /* + * Configure the cache for model and datasource caches. This cache + * configuration is used to store schema descriptions, and table listings + * in connections. + * Duration will be set to '+2 minutes' in bootstrap.php when debug = true + */ + '_cake_model_' => [ + 'className' => FileEngine::class, + 'prefix' => 'myapp_cake_model_', + 'path' => CACHE . 'models' . DS, + 'serialize' => true, + 'duration' => '+1 years', + 'url' => env('CACHE_CAKEMODEL_URL', null), + ], + + /* + * Configure the cache for routes. The cached routes collection is built the + * first time the routes are processed through `config/routes.php`. + * Duration will be set to '+2 seconds' in bootstrap.php when debug = true + */ + '_cake_routes_' => [ + 'className' => FileEngine::class, + 'prefix' => 'myapp_cake_routes_', + 'path' => CACHE, + 'serialize' => true, + 'duration' => '+1 years', + 'url' => env('CACHE_CAKEROUTES_URL', null), + ], + ], + + /* + * Configure the Error and Exception handlers used by your application. + * + * By default errors are displayed using Debugger, when debug is true and logged + * by Cake\Log\Log when debug is false. + * + * In CLI environments exceptions will be printed to stderr with a backtrace. + * In web environments an HTML page will be displayed for the exception. + * With debug true, framework errors like Missing Controller will be displayed. + * When debug is false, framework errors will be coerced into generic HTTP errors. + * + * Options: + * + * - `errorLevel` - int - The level of errors you are interested in capturing. + * - `trace` - boolean - Whether or not backtraces should be included in + * logged errors/exceptions. + * - `log` - boolean - Whether or not you want exceptions logged. + * - `exceptionRenderer` - string - The class responsible for rendering + * uncaught exceptions. If you choose a custom class you should place + * the file for that class in src/Error. This class needs to implement a + * render method. + * - `skipLog` - array - List of exceptions to skip for logging. Exceptions that + * extend one of the listed exceptions will also be skipped for logging. + * E.g.: + * `'skipLog' => ['Cake\Http\Exception\NotFoundException', 'Cake\Http\Exception\UnauthorizedException']` + * - `extraFatalErrorMemory` - int - The number of megabytes to increase + * the memory limit by when a fatal error is encountered. This allows + * breathing room to complete logging or error handling. + */ + 'Error' => [ + 'errorLevel' => E_ALL, + 'exceptionRenderer' => ExceptionRenderer::class, + 'skipLog' => [], + 'log' => true, + 'trace' => true, + ], + + /* + * Email configuration. + * + * By defining transports separately from delivery profiles you can easily + * re-use transport configuration across multiple profiles. + * + * You can specify multiple configurations for production, development and + * testing. + * + * Each transport needs a `className`. Valid options are as follows: + * + * Mail - Send using PHP mail function + * Smtp - Send using SMTP + * Debug - Do not send the email, just return the result + * + * You can add custom transports (or override existing transports) by adding the + * appropriate file to src/Mailer/Transport. Transports should be named + * 'YourTransport.php', where 'Your' is the name of the transport. + */ + 'EmailTransport' => [ + 'default' => [ + 'className' => MailTransport::class, + /* + * The keys host, port, timeout, username, password, client and tls + * are used in SMTP transports + */ + 'host' => 'localhost', + 'port' => 25, + 'timeout' => 30, + /* + * It is recommended to set these options through your environment or app_local.php + */ + //'username' => null, + //'password' => null, + 'client' => null, + 'tls' => false, + 'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null), + ], + ], + + /* + * Email delivery profiles + * + * Delivery profiles allow you to predefine various properties about email + * messages from your application and give the settings a name. This saves + * duplication across your application and makes maintenance and development + * easier. Each profile accepts a number of keys. See `Cake\Mailer\Email` + * for more information. + */ + 'Email' => [ + 'default' => [ + 'transport' => 'default', + 'from' => 'you@localhost', + /* + * Will by default be set to config value of App.encoding, if that exists otherwise to UTF-8. + */ + //'charset' => 'utf-8', + //'headerCharset' => 'utf-8', + ], + ], + + /* + * Connection information used by the ORM to connect + * to your application's datastores. + * + * ### Notes + * - Drivers include Mysql Postgres Sqlite Sqlserver + * See vendor\cakephp\cakephp\src\Database\Driver for complete list + * - Do not use periods in database name - it may lead to error. + * See https://github.com/cakephp/cakephp/issues/6471 for details. + * - 'encoding' is recommended to be set to full UTF-8 4-Byte support. + * E.g set it to 'utf8mb4' in MariaDB and MySQL and 'utf8' for any + * other RDBMS. + */ + 'Datasources' => [ + /** + * These configurations should contain permanent settings used + * by all environments. + * + * The values in app_local.php will override any values set here + * and should be used for local and per-environment configurations. + * + * Environment variable based configurations can be loaded here or + * in app_local.php depending on the applications needs. + */ + 'default' => [ + 'className' => Connection::class, + 'driver' => Mysql::class, + 'persistent' => false, + 'timezone' => 'UTC', + + /** + * For MariaDB/MySQL the internal default changed from utf8 to utf8mb4, aka full utf-8 support, in CakePHP 3.6 + */ + //'encoding' => 'utf8mb4', + + /** + * If your MySQL server is configured with `skip-character-set-client-handshake` + * then you MUST use the `flags` config to set your charset encoding. + * For e.g. `'flags' => [\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4']` + */ + 'flags' => [], + 'cacheMetadata' => true, + 'log' => false, + + /* + * Set identifier quoting to true if you are using reserved words or + * special characters in your table or column names. Enabling this + * setting will result in queries built using the Query Builder having + * identifiers quoted when creating SQL. It should be noted that this + * decreases performance because each query needs to be traversed and + * manipulated before being executed. + */ + 'quoteIdentifiers' => false, + + /* + * During development, if using MySQL < 5.6, uncommenting the + * following line could boost the speed at which schema metadata is + * fetched from the database. It can also be set directly with the + * mysql configuration directive 'innodb_stats_on_metadata = 0' + * which is the recommended value in production environments + */ + //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'], + ], + /* + * The test connection is used during the test suite. + */ + 'test' => [ + 'className' => Connection::class, + 'driver' => Mysql::class, + 'persistent' => false, + 'timezone' => 'UTC', + //'encoding' => 'utf8mb4', + 'flags' => [], + 'cacheMetadata' => true, + 'quoteIdentifiers' => false, + 'log' => false, + //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'], + ], + ], + + /* + * Configures logging options + */ + 'Log' => [ + 'debug' => [ + 'className' => FileLog::class, + 'path' => LOGS, + 'file' => 'debug', + 'url' => env('LOG_DEBUG_URL', null), + 'scopes' => false, + 'levels' => ['notice', 'info', 'debug'], + ], + 'error' => [ + 'className' => FileLog::class, + 'path' => LOGS, + 'file' => 'error', + 'url' => env('LOG_ERROR_URL', null), + 'scopes' => false, + 'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'], + ], + // To enable this dedicated query log, you need set your datasource's log flag to true + 'queries' => [ + 'className' => FileLog::class, + 'path' => LOGS, + 'file' => 'queries', + 'url' => env('LOG_QUERIES_URL', null), + 'scopes' => ['queriesLog'], + ], + ], + + /* + * Session configuration. + * + * Contains an array of settings to use for session configuration. The + * `defaults` key is used to define a default preset to use for sessions, any + * settings declared here will override the settings of the default config. + * + * ## Options + * + * - `cookie` - The name of the cookie to use. Defaults to value set for `session.name` php.ini config. + * Avoid using `.` in cookie names, as PHP will drop sessions from cookies with `.` in the name. + * - `cookiePath` - The url path for which session cookie is set. Maps to the + * `session.cookie_path` php.ini config. Defaults to base path of app. + * - `timeout` - The time in minutes the session should be valid for. + * Pass 0 to disable checking timeout. + * Please note that php.ini's session.gc_maxlifetime must be equal to or greater + * than the largest Session['timeout'] in all served websites for it to have the + * desired effect. + * - `defaults` - The default configuration set to use as a basis for your session. + * There are four built-in options: php, cake, cache, database. + * - `handler` - Can be used to enable a custom session handler. Expects an + * array with at least the `engine` key, being the name of the Session engine + * class to use for managing the session. CakePHP bundles the `CacheSession` + * and `DatabaseSession` engines. + * - `ini` - An associative array of additional ini values to set. + * + * The built-in `defaults` options are: + * + * - 'php' - Uses settings defined in your php.ini. + * - 'cake' - Saves session files in CakePHP's /tmp directory. + * - 'database' - Uses CakePHP's database sessions. + * - 'cache' - Use the Cache class to save sessions. + * + * To define a custom session handler, save it at src/Network/Session/.php. + * Make sure the class implements PHP's `SessionHandlerInterface` and set + * Session.handler to + * + * To use database sessions, load the SQL file located at config/schema/sessions.sql + */ + 'Session' => [ + 'defaults' => 'php', + ], +]; diff --git a/app/config/app_local.example.php b/app/config/app_local.example.php new file mode 100644 index 0000000..affb8e2 --- /dev/null +++ b/app/config/app_local.example.php @@ -0,0 +1,92 @@ + filter_var(env('DEBUG', true), FILTER_VALIDATE_BOOLEAN), + + /* + * Security and encryption configuration + * + * - salt - A random string used in security hashing methods. + * The salt value is also used as the encryption key. + * You should treat it as extremely sensitive data. + */ + 'Security' => [ + 'salt' => env('SECURITY_SALT', '__SALT__'), + ], + + /* + * Connection information used by the ORM to connect + * to your application's datastores. + * + * See app.php for more configuration options. + */ + 'Datasources' => [ + 'default' => [ + 'host' => 'localhost', + /* + * CakePHP will use the default DB port based on the driver selected + * MySQL on MAMP uses port 8889, MAMP users will want to uncomment + * the following line and set the port accordingly + */ + //'port' => 'non_standard_port_number', + + 'username' => 'my_app', + 'password' => 'secret', + + 'database' => 'my_app', + /** + * If not using the default 'public' schema with the PostgreSQL driver + * set it here. + */ + //'schema' => 'myapp', + + /** + * You can use a DSN string to set the entire configuration + */ + 'url' => env('DATABASE_URL', null), + ], + /* + * The test connection is used during the test suite. + */ + 'test' => [ + 'host' => 'localhost', + //'port' => 'non_standard_port_number', + 'username' => 'my_app', + 'password' => 'secret', + 'database' => 'test_myapp', + //'schema' => 'myapp', + ], + ], + + /* + * Email configuration. + * + * Host and credential configuration in case you are using SmtpTransport + * + * See app.php for more configuration options. + */ + 'EmailTransport' => [ + 'default' => [ + 'host' => 'localhost', + 'port' => 25, + 'username' => null, + 'password' => null, + 'client' => null, + 'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null), + ], + ], +]; diff --git a/app/config/bootstrap.php b/app/config/bootstrap.php new file mode 100644 index 0000000..615df3d --- /dev/null +++ b/app/config/bootstrap.php @@ -0,0 +1,215 @@ +parse() +// ->putenv() +// ->toEnv() +// ->toServer(); +// } + +/* + * Read configuration file and inject configuration into various + * CakePHP classes. + * + * By default there is only one configuration file. It is often a good + * idea to create multiple configuration files, and separate the configuration + * that changes from configuration that does not. This makes deployment simpler. + */ +try { + Configure::config('default', new PhpConfig()); + Configure::load('app', 'default', false); +} catch (\Exception $e) { + exit($e->getMessage() . "\n"); +} + +/* + * Load an environment local configuration file to provide overrides to your configuration. + * Notice: For security reasons app_local.php **should not** be included in your git repo. + */ +if (file_exists(CONFIG . 'app_local.php')) { + Configure::load('app_local', 'default'); +} + +/* + * When debug = true the metadata cache should only last + * for a short time. + */ +if (Configure::read('debug')) { + Configure::write('Cache._cake_model_.duration', '+2 minutes'); + Configure::write('Cache._cake_core_.duration', '+2 minutes'); + // disable router cache during development + Configure::write('Cache._cake_routes_.duration', '+2 seconds'); +} + +/* + * Set the default server timezone. Using UTC makes time calculations / conversions easier. + * Check http://php.net/manual/en/timezones.php for list of valid timezone strings. + */ +date_default_timezone_set(Configure::read('App.defaultTimezone')); + +/* + * Configure the mbstring extension to use the correct encoding. + */ +mb_internal_encoding(Configure::read('App.encoding')); + +/* + * Set the default locale. This controls how dates, number and currency is + * formatted and sets the default language to use for translations. + */ +ini_set('intl.default_locale', Configure::read('App.defaultLocale')); + +/* + * Register application error and exception handlers. + */ +$isCli = PHP_SAPI === 'cli'; +if ($isCli) { + (new ConsoleErrorHandler(Configure::read('Error')))->register(); +} else { + (new ErrorHandler(Configure::read('Error')))->register(); +} + +/* + * Include the CLI bootstrap overrides. + */ +if ($isCli) { + require __DIR__ . '/bootstrap_cli.php'; +} + +/* + * Set the full base URL. + * This URL is used as the base of all absolute links. + */ +$fullBaseUrl = Configure::read('App.fullBaseUrl'); +if (!$fullBaseUrl) { + $s = null; + if (env('HTTPS')) { + $s = 's'; + } + + $httpHost = env('HTTP_HOST'); + if (isset($httpHost)) { + $fullBaseUrl = 'http' . $s . '://' . $httpHost; + } + unset($httpHost, $s); +} +if ($fullBaseUrl) { + Router::fullBaseUrl($fullBaseUrl); +} +unset($fullBaseUrl); + +Cache::setConfig(Configure::consume('Cache')); +ConnectionManager::setConfig(Configure::consume('Datasources')); +TransportFactory::setConfig(Configure::consume('EmailTransport')); +Mailer::setConfig(Configure::consume('Email')); +Log::setConfig(Configure::consume('Log')); +Security::setSalt(Configure::consume('Security.salt')); + +/* + * Setup detectors for mobile and tablet. + */ +ServerRequest::addDetector('mobile', function ($request) { + $detector = new \Detection\MobileDetect(); + + return $detector->isMobile(); +}); +ServerRequest::addDetector('tablet', function ($request) { + $detector = new \Detection\MobileDetect(); + + return $detector->isTablet(); +}); + +/* + * You can set whether the ORM uses immutable or mutable Time types. + * The default changed in 4.0 to immutable types. You can uncomment + * below to switch back to mutable types. + * + * You can enable default locale format parsing by adding calls + * to `useLocaleParser()`. This enables the automatic conversion of + * locale specific date formats. For details see + * @link https://book.cakephp.org/4/en/core-libraries/internationalization-and-localization.html#parsing-localized-datetime-data + */ +// TypeFactory::build('time') +// ->useMutable(); +// TypeFactory::build('date') +// ->useMutable(); +// TypeFactory::build('datetime') +// ->useMutable(); +// TypeFactory::build('timestamp') +// ->useMutable(); +// TypeFactory::build('datetimefractional') +// ->useMutable(); +// TypeFactory::build('timestampfractional') +// ->useMutable(); +// TypeFactory::build('datetimetimezone') +// ->useMutable(); +// TypeFactory::build('timestamptimezone') +// ->useMutable(); + +/* + * Custom Inflector rules, can be set to correctly pluralize or singularize + * table, model, controller names or whatever other string is passed to the + * inflection functions. + */ +//Inflector::rules('plural', ['/^(inflect)or$/i' => '\1ables']); +//Inflector::rules('irregular', ['red' => 'redlings']); +//Inflector::rules('uninflected', ['dontinflectme']); +//Inflector::rules('transliteration', ['/å/' => 'aa']); diff --git a/app/config/bootstrap_cli.php b/app/config/bootstrap_cli.php new file mode 100644 index 0000000..7cece95 --- /dev/null +++ b/app/config/bootstrap_cli.php @@ -0,0 +1,31 @@ + '
  • {{text}}
  • ', + 'prevActive' => '
  • {{text}}
  • ', + 'nextDisabled' => '
  • {{text}}
  • ', + 'nextActive' => '
  • {{text}}
  • ', + 'number' => '
  • {{text}}
  • ', + 'sortAsc' => '{{text}} ', + 'sortDesc' => '{{text}} ' + +]; diff --git a/app/config/paths.php b/app/config/paths.php new file mode 100644 index 0000000..7e40e9c --- /dev/null +++ b/app/config/paths.php @@ -0,0 +1,94 @@ += 50.1 is needed to use CakePHP. Please update the `libicu` package of your system.' . PHP_EOL, E_USER_ERROR); +} + +/* + * You can remove this if you are confident you have mbstring installed. + */ +if (!extension_loaded('mbstring')) { + trigger_error('You must enable the mbstring extension to use CakePHP.', E_USER_ERROR); +} diff --git a/app/config/routes.php b/app/config/routes.php new file mode 100644 index 0000000..46b8a9a --- /dev/null +++ b/app/config/routes.php @@ -0,0 +1,99 @@ +setRouteClass(DashedRoute::class); + +$routes->scope('/', function (RouteBuilder $builder) { + $builder->setExtensions(['json']); + // Register scoped middleware for in scopes. + $builder->registerMiddleware('csrf', new CsrfProtectionMiddleware([ + 'httpOnly' => true, + ])); + + /* + * Apply a middleware to the current route scope. + * Requires middleware to be registered through `Application::routes()` with `registerMiddleware()` + */ + $builder->applyMiddleware('csrf'); + + /* + * Here, we are connecting '/' (base path) to a controller called 'Pages', + * its action called 'display', and we pass a param to select the view file + * to use (in this case, templates/Pages/home.php)... + */ + $builder->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']); + + /* + * ...and connect the rest of 'Pages' controller's URLs. + */ + $builder->connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']); + + /* + * Connect catchall routes for all controllers. + * + * The `fallbacks` method is a shortcut for + * + * ``` + * $builder->connect('/:controller', ['action' => 'index']); + * $builder->connect('/:controller/:action/*', []); + * ``` + * + * You can remove these routes once you've connected the + * routes you want in your application. + */ + $builder->fallbacks(); +}); + +/* + * If you need a different set of middleware or none at all, + * open new scope and define routes there. + * + * ``` + * $routes->scope('/api', function (RouteBuilder $builder) { + * // No $builder->applyMiddleware() here. + * // Connect API actions here. + * }); + * ``` + */ diff --git a/app/config/schema/i18n.sql b/app/config/schema/i18n.sql new file mode 100644 index 0000000..e59d1e6 --- /dev/null +++ b/app/config/schema/i18n.sql @@ -0,0 +1,18 @@ +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# +# Licensed under The MIT License +# For full copyright and license information, please see the LICENSE.txt +# Redistributions of files must retain the above copyright notice. +# MIT License (https://opensource.org/licenses/mit-license.php) + +CREATE TABLE i18n ( + id int NOT NULL auto_increment, + locale varchar(6) NOT NULL, + model varchar(255) NOT NULL, + foreign_key int(10) NOT NULL, + field varchar(255) NOT NULL, + content text, + PRIMARY KEY (id), + UNIQUE INDEX I18N_LOCALE_FIELD(locale, model, foreign_key, field), + INDEX I18N_FIELD(model, foreign_key, field) +); diff --git a/app/config/schema/sessions.sql b/app/config/schema/sessions.sql new file mode 100644 index 0000000..1aa0a0f --- /dev/null +++ b/app/config/schema/sessions.sql @@ -0,0 +1,15 @@ +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# +# Licensed under The MIT License +# For full copyright and license information, please see the LICENSE.txt +# Redistributions of files must retain the above copyright notice. +# MIT License (https://opensource.org/licenses/mit-license.php) + +CREATE TABLE `sessions` ( + `id` char(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, + `created` datetime DEFAULT CURRENT_TIMESTAMP, -- optional, requires MySQL 5.6.5+ + `modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- optional, requires MySQL 5.6.5+ + `data` blob DEFAULT NULL, -- for PostgreSQL use bytea instead of blob + `expires` int(10) unsigned DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/app/index.php b/app/index.php new file mode 100644 index 0000000..4591769 --- /dev/null +++ b/app/index.php @@ -0,0 +1,16 @@ + + + + + + + + + + + tests/TestCase/ + + + + + + + + + + + + + + + + + src/ + plugins/*/src/ + + src/Console/Installer.php + + + + diff --git a/app/plugins/.gitkeep b/app/plugins/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/resources/.gitkeep b/app/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/Application.php b/app/src/Application.php new file mode 100644 index 0000000..6c47b27 --- /dev/null +++ b/app/src/Application.php @@ -0,0 +1,108 @@ +bootstrapCli(); + } + + /* + * Only try to load DebugKit in development mode + * Debug Kit should not be installed on a production system + */ + if (Configure::read('debug')) { + $this->addPlugin('DebugKit'); + } + + // Load more plugins here + } + + /** + * Setup the middleware queue your application will use. + * + * @param \Cake\Http\MiddlewareQueue $middlewareQueue The middleware queue to setup. + * @return \Cake\Http\MiddlewareQueue The updated middleware queue. + */ + public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue + { + $middlewareQueue + // Catch any exceptions in the lower layers, + // and make an error page/response + ->add(new ErrorHandlerMiddleware(Configure::read('Error'))) + + // Handle plugin/theme assets like CakePHP normally does. + ->add(new AssetMiddleware([ + 'cacheTime' => Configure::read('Asset.cacheTime'), + ])) + + // Add routing middleware. + // If you have a large number of routes connected, turning on routes + // caching in production could improve performance. For that when + // creating the middleware instance specify the cache config name by + // using it's second constructor argument: + // `new RoutingMiddleware($this, '_cake_routes_')` + ->add(new RoutingMiddleware($this)); + + return $middlewareQueue; + } + + /** + * Bootrapping for CLI application. + * + * That is when running commands. + * + * @return void + */ + protected function bootstrapCli(): void + { + try { + $this->addPlugin('Bake'); + } catch (MissingPluginException $e) { + // Do not halt if the plugin is missing + } + + $this->addPlugin('Migrations'); + + // Load more plugins here + } +} diff --git a/app/src/Command/ConsoleCommand.php b/app/src/Command/ConsoleCommand.php new file mode 100644 index 0000000..e65fe09 --- /dev/null +++ b/app/src/Command/ConsoleCommand.php @@ -0,0 +1,86 @@ +err('Unable to load Psy\Shell.'); + $io->err(''); + $io->err('Make sure you have installed psysh as a dependency,'); + $io->err('and that Psy\Shell is registered in your autoloader.'); + $io->err(''); + $io->err('If you are using composer run'); + $io->err(''); + $io->err('$ php composer.phar require --dev psy/psysh'); + $io->err(''); + + return static::CODE_ERROR; + } + + $io->out("You can exit with `CTRL-C` or `exit`"); + $io->out(''); + + Log::drop('debug'); + Log::drop('error'); + $io->setLoggers(false); + restore_error_handler(); + restore_exception_handler(); + + $psy = new PsyShell(); + $psy->run(); + } + + /** + * Display help for this console. + * + * @param \Cake\Console\ConsoleOptionParser $parser The parser to update + * @return \Cake\Console\ConsoleOptionParser + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + $parser->setDescription( + 'This shell provides a REPL that you can use to interact with ' . + 'your application in a command line designed to run PHP code. ' . + 'You can use it to run adhoc queries with your models, or ' . + 'explore the features of CakePHP and your application.' . + "\n\n" . + 'You will need to have psysh installed for this Shell to work.' + ); + + return $parser; + } +} diff --git a/app/src/Console/Installer.php b/app/src/Console/Installer.php new file mode 100644 index 0000000..8d98c77 --- /dev/null +++ b/app/src/Console/Installer.php @@ -0,0 +1,246 @@ +getIO(); + + $rootDir = dirname(dirname(__DIR__)); + + static::createAppLocalConfig($rootDir, $io); + static::createWritableDirectories($rootDir, $io); + + static::setFolderPermissions($rootDir, $io); + static::setSecuritySalt($rootDir, $io); + + $class = 'Cake\Codeception\Console\Installer'; + if (class_exists($class)) { + $class::customizeCodeceptionBinary($event); + } + } + + /** + * Create config/app_local.php file if it does not exist. + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @return void + */ + public static function createAppLocalConfig($dir, $io) + { + $appLocalConfig = $dir . '/config/app_local.php'; + $appLocalConfigTemplate = $dir . '/config/app_local.example.php'; + if (!file_exists($appLocalConfig)) { + copy($appLocalConfigTemplate, $appLocalConfig); + $io->write('Created `config/app_local.php` file'); + } + } + + /** + * Create the `logs` and `tmp` directories. + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @return void + */ + public static function createWritableDirectories($dir, $io) + { + foreach (static::WRITABLE_DIRS as $path) { + $path = $dir . '/' . $path; + if (!file_exists($path)) { + mkdir($path); + $io->write('Created `' . $path . '` directory'); + } + } + } + + /** + * Set globally writable permissions on the "tmp" and "logs" directory. + * + * This is not the most secure default, but it gets people up and running quickly. + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @return void + */ + public static function setFolderPermissions($dir, $io) + { + // ask if the permissions should be changed + if ($io->isInteractive()) { + $validator = function ($arg) { + if (in_array($arg, ['Y', 'y', 'N', 'n'])) { + return $arg; + } + throw new Exception('This is not a valid answer. Please choose Y or n.'); + }; + $setFolderPermissions = $io->askAndValidate( + 'Set Folder Permissions ? (Default to Y) [Y,n]? ', + $validator, + 10, + 'Y' + ); + + if (in_array($setFolderPermissions, ['n', 'N'])) { + return; + } + } + + // Change the permissions on a path and output the results. + $changePerms = function ($path) use ($io) { + $currentPerms = fileperms($path) & 0777; + $worldWritable = $currentPerms | 0007; + if ($worldWritable == $currentPerms) { + return; + } + + $res = chmod($path, $worldWritable); + if ($res) { + $io->write('Permissions set on ' . $path); + } else { + $io->write('Failed to set permissions on ' . $path); + } + }; + + $walker = function ($dir) use (&$walker, $changePerms) { + $files = array_diff(scandir($dir), ['.', '..']); + foreach ($files as $file) { + $path = $dir . '/' . $file; + + if (!is_dir($path)) { + continue; + } + + $changePerms($path); + $walker($path); + } + }; + + $walker($dir . '/tmp'); + $changePerms($dir . '/tmp'); + $changePerms($dir . '/logs'); + } + + /** + * Set the security.salt value in the application's config file. + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @return void + */ + public static function setSecuritySalt($dir, $io) + { + $newKey = hash('sha256', Security::randomBytes(64)); + static::setSecuritySaltInFile($dir, $io, $newKey, 'app_local.php'); + } + + /** + * Set the security.salt value in a given file + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @param string $newKey key to set in the file + * @param string $file A path to a file relative to the application's root + * @return void + */ + public static function setSecuritySaltInFile($dir, $io, $newKey, $file) + { + $config = $dir . '/config/' . $file; + $content = file_get_contents($config); + + $content = str_replace('__SALT__', $newKey, $content, $count); + + if ($count == 0) { + $io->write('No Security.salt placeholder to replace.'); + + return; + } + + $result = file_put_contents($config, $content); + if ($result) { + $io->write('Updated Security.salt value in config/' . $file); + + return; + } + $io->write('Unable to update Security.salt value.'); + } + + /** + * Set the APP_NAME value in a given file + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @param string $appName app name to set in the file + * @param string $file A path to a file relative to the application's root + * @return void + */ + public static function setAppNameInFile($dir, $io, $appName, $file) + { + $config = $dir . '/config/' . $file; + $content = file_get_contents($config); + $content = str_replace('__APP_NAME__', $appName, $content, $count); + + if ($count == 0) { + $io->write('No __APP_NAME__ placeholder to replace.'); + + return; + } + + $result = file_put_contents($config, $content); + if ($result) { + $io->write('Updated __APP_NAME__ value in config/' . $file); + + return; + } + $io->write('Unable to update __APP_NAME__ value.'); + } +} diff --git a/app/src/Controller/AlignmentsController.php b/app/src/Controller/AlignmentsController.php new file mode 100644 index 0000000..d025cf0 --- /dev/null +++ b/app/src/Controller/AlignmentsController.php @@ -0,0 +1,130 @@ +Alignments->find(); + if (!empty($organisation_id)) { + $query->where(['organisation_id' => $organisation_id]); + } + if ($this->_isRest()) { + $alignments = $query->all(); + return $this->RestResponse->viewData($alignments, 'json'); + } else { + $this->loadComponent('Paginator'); + $alignments = $this->Paginator->paginate($query); + $this->set('data', $alignments); + $this->set('metaGroup', 'ContactDB'); + } + } + + public function view($id) + { + if (empty($id)) { + throw new NotFoundException(__('Invalid alignment.')); + } + $individual = $this->Alignments->get($id); + if ($this->_isRest()) { + return $this->RestResponse->viewData($individual, 'json'); + } else { + + } + $this->set('metaGroup', 'ContactDB'); + $this->set('alignment', $individual); + } + + public function delete($id) + { + if (empty($id)) { + throw new NotFoundException(__('Invalid alignment.')); + } + $individual = $this->Alignments->get($id); + if ($this->request->is('post') || $this->request->is('delete')) { + if ($this->Alignments->delete($individual)) { + $message = __('Individual deleted.'); + if ($this->_isRest()) { + $individual = $this->Alignments->get($id); + return $this->RestResponse->saveSuccessResponse('Alignments', 'delete', $id, 'json', $message); + } else { + $this->Flash->success($message); + return $this->redirect($this->referer()); + } + } + } + $this->set('metaGroup', 'ContactDB'); + $this->set('scope', 'alignments'); + $this->set('id', $individual['id']); + $this->set('alignment', $individual); + $this->viewBuilder()->setLayout('ajax'); + $this->render('/genericTemplates/delete'); + } + + public function add($scope, $source_id) + { + if (empty($scope) || empty($source_id)) { + throw new NotAcceptableException(__('Invalid input. scope and source_id expected as URL parameters in the format /alignments/add/[scope]/[source_id].')); + } + $this->loadModel('Individuals'); + $this->loadModel('Organisations'); + $alignment = $this->Alignments->newEmptyEntity(); + if ($this->request->is('post')) { + $this->Alignments->patchEntity($alignment, $this->request->getData()); + if ($scope === 'individuals') { + $alignment['individual_id'] = $source_id; + } else { + $alignment['organisation_id'] = $source_id; + } + if ($this->Alignments->save($alignment)) { + $message = __('Alignment added.'); + if ($this->_isRest()) { + $alignment = $this->Alignments->get($this->Alignments->id); + return $this->RestResponse->viewData($alignment, 'json'); + } else { + $this->Flash->success($message); + $this->redirect($this->referer()); + } + } else { + $message = __('Alignment could not be added.'); + if ($this->_isRest()) { + return $this->RestResponse->saveFailResponse('Individuals', 'addAlignment', false, $message); + } else { + $this->Flash->error($message); + //$this->redirect($this->referer()); + } + } + } + if ($scope === 'organisations') { + $individuals = $this->Individuals->find('list', ['valueField' => 'email']); + $this->set('individuals', $individuals); + $organisation = $this->Organisations->find()->where(['id' => $source_id])->first(); + if (empty($organisation)) { + throw new NotFoundException(__('Invalid organisation')); + } + $this->set(compact('organisation')); + } else { + $organisations = $this->Organisations->find('list', ['valueField' => 'name']); + $this->set('organisations', $organisations); + $individual = $this->Individuals->find()->where(['id' => $source_id])->first(); + if (empty($individual)) { + throw new NotFoundException(__('Invalid individual')); + } + $this->set(compact('individual')); + } + $this->set(compact('alignment')); + $this->set('scope', $scope); + $this->set('source_id', $source_id); + $this->set('metaGroup', 'ContactDB'); + } +} diff --git a/app/src/Controller/AppController.php b/app/src/Controller/AppController.php new file mode 100644 index 0000000..bc52bde --- /dev/null +++ b/app/src/Controller/AppController.php @@ -0,0 +1,104 @@ +loadComponent('FormProtection');` + * + * @return void + */ + public function initialize(): void + { + parent::initialize(); + + $this->loadComponent('RequestHandler'); + $this->loadComponent('Flash'); + $this->loadComponent('RestResponse'); + $this->loadComponent('ACL'); + + if (Configure::read('debug')) { + Configure::write('DebugKit.panels', ['DebugKit.Packages' => true]); + Configure::write('DebugKit.forceEnable', true); + } + + /* + * Enable the following component for recommended CakePHP form protection settings. + * see https://book.cakephp.org/4/en/controllers/components/form-protection.html + */ + //$this->loadComponent('FormProtection'); + } + + public function beforeFilter(EventInterface $event) + { + $this->set('ajax', $this->request->is('ajax')); + } + + protected function _isRest() + { + // This method is surprisingly slow and called many times for one request, so it make sense to cache the result. + if ($this->isRest !== null) { + return $this->isRest; + } + if ($this->request->is('json')) { + if (!empty($this->request->input()) && empty($this->request->input('json_decode'))) { + throw new MethodNotAllowedException('Invalid JSON input. Make sure that the JSON input is a correctly formatted JSON string. This request has been blocked to avoid an unfiltered request.'); + } + $this->isRest = true; + return true; + } else { + $this->isRest = false; + return false; + } + } + + protected function _isJson($data) + { + return (json_decode($data) != null) ? true : false; + } + + public function generateUUID() + { + $uuid = Text::uuid(); + return $this->RestResponse->viewData(['uuid' => $uuid], 'json'); + } +} diff --git a/app/src/Controller/Component/.gitkeep b/app/src/Controller/Component/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/Controller/Component/ACLComponent.php b/app/src/Controller/Component/ACLComponent.php new file mode 100644 index 0000000..8fddcdf --- /dev/null +++ b/app/src/Controller/Component/ACLComponent.php @@ -0,0 +1,875 @@ + array()) - any role in the array has access + // $action == array('AND' => array()) - roles with all permissions in the array have access + // If we add any new functionality to MISP and we don't add it to this list, it will only be visible to site admins. + private $__aclList = array( + '*' => array( + 'blackhole' => array(), + 'checkAction' => array(), + 'checkAuthUser' => array(), + 'checkExternalAuthUser' => array(), + 'cleanModelCaches' => array(), + 'debugACL' => array(), + 'generateCount' => array(), + 'getActions' => array(), + 'pruneDuplicateUUIDs' => array(), + 'queryACL' => array(), + 'removeDuplicateEvents' => array(), + 'restSearch' => array('*'), + 'updateDatabase' => array(), + 'upgrade2324' => array(), + ), + 'attributes' => array( + 'add' => array('perm_add'), + 'add_attachment' => array('perm_add'), + 'add_threatconnect' => array('perm_add'), + 'addTag' => array('perm_tagger'), + 'attributeReplace' => array('perm_add'), + 'attributeStatistics' => array('*'), + 'bro' => array('*'), + 'checkAttachments' => array(), + 'checkComposites' => array('perm_admin'), + 'checkOrphanedAttributes' => array(), + 'delete' => array('perm_add'), + 'deleteSelected' => array('perm_add'), + 'describeTypes' => array('*'), + 'download' => array('*'), + 'downloadAttachment' => array('*'), + 'downloadSample' => array('*'), + 'edit' => array('perm_add'), + 'editField' => array('perm_add'), + 'editSelected' => array('perm_add'), + 'exportSearch' => array('*'), + 'fetchEditForm' => array('perm_add'), + 'fetchViewValue' => array('*'), + 'generateCorrelation' => array(), + 'hoverEnrichment' => array('perm_add'), + 'index' => array('*'), + 'pruneOrphanedAttributes' => array(), + 'removeTag' => array('perm_tagger'), + 'reportValidationIssuesAttributes' => array(), + 'restore' => array('perm_add'), + 'restSearch' => array('*'), + 'returnAttributes' => array('*'), + 'rpz' => array('*'), + 'search' => array('*'), + 'searchAlternate' => array('*'), + 'toggleCorrelation' => array('perm_add'), + 'text' => array('*'), + 'toggleToIDS' => array('perm_add'), + 'updateAttributeValues' => array('perm_add'), + 'view' => array('*'), + 'viewPicture' => array('*'), + ), + 'dashboards' => array( + 'getForm' => array('*'), + 'index' => array('*'), + 'updateSettings' => array('*'), + 'getEmptyWidget' => array('*'), + 'renderWidget' => array('*'), + 'listTemplates' => array('*'), + 'saveTemplate' => array('*'), + 'export' => array('*'), + 'import' => array('*'), + 'deleteTemplate' => array('*') + ), + 'decayingModel' => array( + "update" => array(), + "export" => array('*'), + "import" => array('*'), + "view" => array('*'), + "index" => array('*'), + "add" => array( 'OR' => array('perm_admin', 'perm_decaying')), + "edit" => array( 'OR' => array('perm_admin', 'perm_decaying')), + "delete" => array( 'OR' => array('perm_admin', 'perm_decaying')), + "enable" => array( 'OR' => array('perm_admin', 'perm_decaying')), + "disable" => array( 'OR' => array('perm_admin', 'perm_decaying')), + "decayingTool" => array( 'OR' => array('perm_admin', 'perm_decaying')), + "getAllDecayingModels" => array('*'), + "decayingToolBasescore" => array('*'), + "decayingToolSimulation" => array('*'), + "decayingToolRestSearch" => array('*'), + "decayingToolComputeSimulation" => array('*') + ), + 'decayingModelMapping' => array( + "viewAssociatedTypes" => array('*'), + "linkAttributeTypeToModel" => array( 'OR' => array('perm_admin', 'perm_decaying')) + ), + 'communities' => array( + 'index' => array(), + 'requestAccess' => array(), + 'view' => array() + ), + 'eventBlacklists' => array( + 'add' => array(), + 'delete' => array(), + 'edit' => array(), + 'index' => array(), + 'massDelete' => array() + ), + 'eventDelegations' => array( + 'acceptDelegation' => array('perm_add'), + 'delegateEvent' => array('perm_delegate'), + 'deleteDelegation' => array('perm_add'), + 'index' => array('*'), + 'view' => array('*'), + ), + 'events' => array( + 'add' => array('perm_add'), + 'addIOC' => array('perm_add'), + 'addTag' => array('perm_tagger'), + 'add_misp_export' => array('perm_modify'), + 'alert' => array('perm_publish'), + 'automation' => array('perm_auth'), + 'checkLocks' => array('perm_add'), + 'checkPublishedStatus' => array('*'), + 'checkuuid' => array('perm_sync'), + 'contact' => array('*'), + 'csv' => array('*'), + 'cullEmptyEvents' => array(), + 'delegation_index' => array('*'), + 'delete' => array('perm_add'), + 'deleteNode' => array('*'), + 'dot' => array(), + 'downloadExport' => array('*'), + 'downloadOpenIOCEvent' => array('*'), + 'edit' => array('perm_add'), + 'enrichEvent' => array('perm_add'), + 'export' => array('*'), + 'exportChoice' => array('*'), + 'exportModule' => array('*'), + 'filterEventIdsForPush' => array('perm_sync'), + 'filterEventIndex' => array('*'), + 'freeTextImport' => array('perm_add'), + 'getEditStrategy' => array('perm_add'), + 'getEventInfoById' => array('*'), + 'getEventGraphReferences' => array('*'), + 'getEventGraphTags' => array('*'), + 'getEventGraphGeneric' => array('*'), + 'getEventTimeline' => array('*'), + 'genDistributionGraph' => array('*'), + 'getDistributionGraph' => array('*'), + 'getReferenceData' => array('*'), + 'getReferences' => array('*'), + 'getObjectTemplate' => array('*'), + 'handleModuleResults' => array('*'), + 'hids' => array('*'), + 'index' => array('*'), + 'importChoice' => array('*'), + 'importModule' => array('*'), + 'massDelete' => array('perm_site_admin'), + 'merge' => array('perm_modify'), + 'nids' => array('*'), + 'proposalEventIndex' => array('*'), + 'publish' => array('perm_publish'), + 'publishSightings' => array('perm_sighting'), + 'pushEventToZMQ' => array('perm_publish_zmq'), + 'pushEventToKafka' => array('perm_publish_kafka'), + 'pushProposals' => array('perm_sync'), + 'queryEnrichment' => array('perm_add'), + 'removePivot' => array('*'), + 'removeTag' => array('perm_tagger'), + 'reportValidationIssuesEvents' => array(), + 'restSearch' => array('*'), + 'saveFreeText' => array('perm_add'), + 'stix' => array('*'), + 'stix2' => array('*'), + 'strposarray' => array(), + 'toggleCorrelation' => array('perm_add'), + 'unpublish' => array('perm_modify'), + 'updateGraph' => array('*'), + 'upload_analysis_file' => array('perm_add'), + 'upload_sample' => array('AND' => array('perm_auth', 'perm_add')), + 'upload_stix' => array('perm_add'), + 'view' => array('*'), + 'viewEventAttributes' => array('*'), + 'viewEventGraph' => array('*'), + 'viewGraph' => array('*'), + 'viewGalaxyMatrix' => array('*'), + 'xml' => array('*') + ), + 'favouriteTags' => array( + 'toggle' => array('*'), + 'getToggleField' => array('*') + ), + 'feeds' => array( + 'add' => array(), + 'cacheFeeds' => array(), + 'compareFeeds' => array('*'), + 'delete' => array(), + 'disable' => array(), + 'edit' => array(), + 'enable' => array(), + 'feedCoverage' => array('*'), + 'fetchFromAllFeeds' => array(), + 'fetchFromFeed' => array(), + 'fetchSelectedFromFreetextIndex' => array(), + 'getEvent' => array(), + 'importFeeds' => array(), + 'index' => array('*'), + 'loadDefaultFeeds' => array('perm_site_admin'), + 'previewEvent' => array('*'), + 'previewIndex' => array('*'), + 'searchCaches' => array('*'), + 'toggleSelected' => array('perm_site_admin'), + 'view' => array('*'), + ), + 'galaxies' => array( + 'attachCluster' => array('perm_tagger'), + 'attachMultipleClusters' => array('perm_tagger'), + 'delete' => array(), + 'index' => array('*'), + 'selectGalaxy' => array('perm_tagger'), + 'selectGalaxyNamespace' => array('perm_tagger'), + 'selectCluster' => array('perm_tagger'), + 'showGalaxies' => array('*'), + 'update' => array(), + 'view' => array('*'), + 'viewGraph' => array('*') + ), + 'galaxyClusters' => array( + 'attachToEvent' => array('perm_tagger'), + 'delete' => array('perm_site_admin'), + 'detach' => array('perm_tagger'), + 'index' => array('*'), + 'view' => array('*'), + 'viewGalaxyMatrix' => array('*') + ), + 'galaxyElements' => array( + 'index' => array('*') + ), + 'jobs' => array( + 'cache' => array('*'), + 'getError' => array(), + 'getGenerateCorrelationProgress' => array('*'), + 'getProgress' => array('*'), + 'index' => array(), + 'clearJobs' => array() + ), + 'logs' => array( + 'admin_index' => array('perm_audit'), + 'admin_search' => array('perm_audit'), + 'event_index' => array('*'), + 'maxDateActivity' => array('*'), + 'returnDates' => array('*'), + 'testForStolenAttributes' => array(), + 'pruneUpdateLogs' => array() + ), + 'modules' => array( + 'index' => array('perm_auth'), + 'queryEnrichment' => array('perm_auth'), + ), + 'news' => array( + 'add' => array(), + 'edit' => array(), + 'delete' => array(), + 'index' => array('*'), + ), + 'noticelists' => array( + 'delete' => array(), + 'enableNoticelist' => array(), + 'getToggleField' => array(), + 'index' => array('*'), + 'toggleEnable' => array(), + 'update' => array(), + 'view' => array('*') + ), + 'objects' => array( + 'add' => array('perm_add'), + 'addValueField' => array('perm_add'), + 'delete' => array('perm_add'), + 'edit' => array('perm_add'), + 'get_row' => array('perm_add'), + 'orphanedObjectDiagnostics' => array(), + 'editField' => array('perm_add'), + 'fetchEditForm' => array('perm_add'), + 'fetchViewValue' => array('*'), + 'quickAddAttributeForm' => array('perm_add'), + 'quickFetchTemplateWithValidObjectAttributes' => array('perm_add'), + 'restSearch' => array('*'), + 'proposeObjectsFromAttributes' => array('*'), + 'groupAttributesIntoObject' => array('perm_add'), + 'revise_object' => array('perm_add'), + 'view' => array('*'), + ), + 'objectReferences' => array( + 'add' => array('perm_add'), + 'delete' => array('perm_add'), + 'view' => array('*'), + ), + 'objectTemplates' => array( + 'activate' => array(), + 'add' => array('perm_object_template'), + 'edit' => array('perm_object_template'), + 'delete' => array('perm_object_template'), + 'getToggleField' => array(), + 'objectChoice' => array('*'), + 'objectMetaChoice' => array('perm_add'), + 'view' => array('*'), + 'viewElements' => array('*'), + 'index' => array('*'), + 'update' => array('perm_site_admin') + ), + 'objectTemplateElements' => array( + 'viewElements' => array('*') + ), + 'orgBlacklists' => array( + 'add' => array(), + 'delete' => array(), + 'edit' => array(), + 'index' => array(), + ), + 'organisations' => array( + 'admin_add' => array(), + 'admin_delete' => array(), + 'admin_edit' => array(), + 'admin_generateuuid' => array(), + 'admin_merge' => array(), + 'fetchOrgsForSG' => array('*'), + 'fetchSGOrgRow' => array('*'), + 'getUUIDs' => array('perm_sync'), + 'index' => array('*'), + 'landingpage' => array('*'), + 'view' => array('*'), + ), + 'pages' => array( + 'display' => array('*'), + ), + 'posts' => array( + 'add' => array('*'), + 'delete' => array('*'), + 'edit' => array('*'), + 'pushMessageToZMQ' => array('perm_site_admin') + ), + 'regexp' => array( + 'admin_add' => array('perm_regexp_access'), + 'admin_clean' => array('perm_regexp_access'), + 'admin_delete' => array('perm_regexp_access'), + 'admin_edit' => array('perm_regexp_access'), + 'admin_index' => array('perm_regexp_access'), + 'cleanRegexModifiers' => array('perm_regexp_access'), + 'index' => array('*'), + ), + 'restClientHistory' => array( + 'delete' => array('*'), + 'index' => array('*') + ), + 'roles' => array( + 'admin_add' => array(), + 'admin_delete' => array(), + 'admin_edit' => array(), + 'admin_index' => array('perm_admin'), + 'admin_set_default' => array(), + 'index' => array('*'), + 'view' => array('*'), + ), + 'servers' => array( + 'add' => array(), + 'dbSchemaDiagnostic' => array(), + 'cache' => array(), + 'changePriority' => array(), + 'checkout' => array(), + 'clearWorkerQueue' => array(), + 'createSync' => array('perm_sync'), + 'delete' => array(), + 'deleteFile' => array(), + 'edit' => array(), + 'fetchServersForSG' => array('*'), + 'filterEventIndex' => array(), + 'getApiInfo' => array('*'), + 'getGit' => array(), + 'getInstanceUUID' => array('perm_sync'), + 'getPyMISPVersion' => array('*'), + 'getRemoteUser' => array(), + 'getSetting' => array(), + 'getSubmodulesStatus' => array(), + 'getSubmoduleQuickUpdateForm' => array(), + 'getWorkers' => array(), + 'getVersion' => array('*'), + 'import' => array(), + 'index' => array(), + 'ondemandAction' => array(), + 'postTest' => array('perm_sync'), + 'previewEvent' => array(), + 'previewIndex' => array(), + 'pull' => array(), + 'purgeSessions' => array(), + 'push' => array(), + 'releaseUpdateLock' => array(), + 'resetRemoteAuthKey' => array(), + 'rest' => array('perm_auth'), + 'restartDeadWorkers' => array(), + 'restartWorkers' => array(), + 'serverSettings' => array(), + 'serverSettingsEdit' => array(), + 'serverSettingsReloadSetting' => array(), + 'startWorker' => array(), + 'startZeroMQServer' => array(), + 'statusZeroMQServer' => array(), + 'stopWorker' => array(), + 'stopZeroMQServer' => array(), + 'testConnection' => array(), + 'update' => array(), + 'updateJSON' => array(), + 'updateProgress' => array(), + 'updateSubmodule' => array(), + 'uploadFile' => array(), + 'viewDeprecatedFunctionUse' => array() + ), + 'shadowAttributes' => array( + 'accept' => array('perm_add'), + 'acceptSelected' => array('perm_add'), + 'add' => array('perm_add'), + 'add_attachment' => array('perm_add'), + 'delete' => array('perm_add'), + 'discard' => array('perm_add'), + 'discardSelected' => array('perm_add'), + 'download' => array('*'), + 'edit' => array('perm_add'), + 'editField' => array('perm_add'), + 'fetchEditForm' => array('perm_add'), + 'generateCorrelation' => array(), + 'getProposalsByUuid' => array('perm_sync'), + 'getProposalsByUuidList' => array('perm_sync'), + 'index' => array('*'), + 'view' => array('*'), + ), + 'sharingGroups' => array( + 'add' => array('perm_sharing_group'), + 'addServer' => array('perm_sharing_group'), + 'addOrg' => array('perm_sharing_group'), + 'delete' => array('perm_sharing_group'), + 'edit' => array('perm_sharing_group'), + 'index' => array('*'), + 'removeServer' => array('perm_sharing_group'), + 'removeOrg' => array('perm_sharing_group'), + 'view' => array('*'), + ), + 'sightings' => array( + 'add' => array('perm_sighting'), + 'restSearch' => array('perm_sighting'), + 'advanced' => array('perm_sighting'), + 'delete' => array('perm_sighting'), + 'index' => array('*'), + 'listSightings' => array('*'), + 'quickDelete' => array('perm_sighting'), + 'viewSightings' => array('*'), + 'bulkSaveSightings' => array('OR' => array('perm_sync', 'perm_sighting')), + 'quickAdd' => array('perm_sighting') + ), + 'sightingdb' => array( + 'add' => array(), + 'edit' => array(), + 'delete' => array(), + 'index' => array(), + 'requestStatus' => array(), + 'search' => array() + ), + 'tagCollections' => array( + 'add' => array('perm_tag_editor'), + 'addTag' => array('perm_tag_editor'), + 'delete' => array('perm_tag_editor'), + 'edit' => array('perm_tag_editor'), + 'getRow' => array('perm_tag_editor'), + 'import' => array('perm_tag_editor'), + 'index' => array('*'), + 'removeTag' => array('perm_tag_editor'), + 'view' => array('*') + ), + 'tags' => array( + 'add' => array('perm_tag_editor'), + 'attachTagToObject' => array('perm_tagger'), + 'delete' => array(), + 'edit' => array(), + 'index' => array('*'), + 'quickAdd' => array('perm_tag_editor'), + 'removeTagFromObject' => array('perm_tagger'), + 'search' => array('*'), + 'selectTag' => array('perm_tagger'), + 'selectTaxonomy' => array('perm_tagger'), + 'showEventTag' => array('*'), + 'showAttributeTag' => array('*'), + 'showTagControllerTag' => array('*'), + 'tagStatistics' => array('*'), + 'view' => array('*'), + 'viewGraph' => array('*'), + 'viewTag' => array('*') + ), + 'tasks' => array( + 'index' => array(), + 'setTask' => array(), + ), + 'taxonomies' => array( + 'addTag' => array(), + 'delete' => array(), + 'disable' => array(), + 'disableTag' => array(), + 'enable' => array(), + 'index' => array('*'), + 'taxonomyMassConfirmation' => array('perm_tagger'), + 'taxonomyMassHide' => array('perm_tagger'), + 'taxonomyMassUnhide' => array('perm_tagger'), + 'toggleRequired' => array('perm_site_admin'), + 'update' => array(), + 'view' => array('*'), + 'unhideTag' => array('perm_tagger'), + 'hideTag' => array('perm_tagger'), + ), + 'templateElements' => array( + 'add' => array('perm_template'), + 'delete' => array('perm_template'), + 'edit' => array('perm_template'), + 'index' => array('*'), + 'templateElementAddChoices' => array('perm_template'), + ), + 'templates' => array( + 'add' => array('perm_template'), + 'delete' => array('perm_template'), + 'deleteTemporaryFile' => array('perm_add'), + 'edit' => array('perm_template'), + 'index' => array('*'), + 'populateEventFromTemplate' => array('perm_add'), + 'saveElementSorting' => array('perm_template'), + 'submitEventPopulation' => array('perm_add'), + 'templateChoices' => array('*'), + 'uploadFile' => array('*'), + 'view' => array('*'), + ), + 'threads' => array( + 'index' => array('*'), + 'view' => array('*'), + 'viewEvent' => array('*'), + ), + 'users' => array( + 'acceptRegistrations' => array('perm_site_admin'), + 'admin_add' => array('perm_admin'), + 'admin_delete' => array('perm_admin'), + 'admin_edit' => array('perm_admin'), + 'admin_email' => array('perm_admin'), + 'admin_filterUserIndex' => array('perm_admin'), + 'admin_index' => array('perm_admin'), + 'admin_monitor' => array('perm_site_admin'), + 'admin_quickEmail' => array('perm_admin'), + 'admin_view' => array('perm_admin'), + 'attributehistogram' => array('*'), + 'change_pw' => array('*'), + 'checkAndCorrectPgps' => array(), + 'checkIfLoggedIn' => array('*'), + 'dashboard' => array('*'), + 'delete' => array('perm_admin'), + 'discardRegistrations' => array('perm_site_admin'), + 'downloadTerms' => array('*'), + 'edit' => array('*'), + 'email_otp' => array('*'), + 'searchGpgKey' => array('*'), + 'fetchGpgKey' => array('*'), + 'histogram' => array('*'), + 'initiatePasswordReset' => array('perm_admin'), + 'login' => array('*'), + 'logout' => array('*'), + 'register' => array('*'), + 'registrations' => array('perm_site_admin'), + 'resetAllSyncAuthKeys' => array(), + 'resetauthkey' => array('*'), + 'request_API' => array('*'), + 'routeafterlogin' => array('*'), + 'statistics' => array('*'), + 'tagStatisticsGraph' => array('*'), + 'terms' => array('*'), + 'updateLoginTime' => array('*'), + 'verifyCertificate' => array(), + 'verifyGPG' => array(), + 'view' => array('*'), + ), + 'userSettings' => array( + 'index' => array('*'), + 'view' => array('*'), + 'setSetting' => array('*'), + 'getSetting' => array('*'), + 'delete' => array('*'), + 'setHomePage' => array('*') + ), + 'warninglists' => array( + 'checkValue' => array('perm_auth'), + 'delete' => array(), + 'enableWarninglist' => array(), + 'getToggleField' => array(), + 'index' => array('*'), + 'toggleEnable' => array(), + 'update' => array(), + 'view' => array('*') + ), + 'whitelists' => array( + 'admin_add' => array('perm_regexp_access'), + 'admin_delete' => array('perm_regexp_access'), + 'admin_edit' => array('perm_regexp_access'), + 'admin_index' => array('perm_regexp_access'), + 'index' => array('*'), + ), + 'eventGraph' => array( + 'view' => array('*'), + 'add' => array('perm_add'), + 'delete' => array('perm_modify'), + ) + ); + + private function __checkLoggedActions($user, $controller, $action) + { + $loggedActions = array( + 'servers' => array( + 'index' => array( + 'role' => array( + 'NOT' => array( + 'perm_site_admin' + ) + ), + 'message' => __('This could be an indication of an attempted privilege escalation on older vulnerable versions of MISP (<2.4.115)') + ) + ) + ); + foreach ($loggedActions as $k => $v) { + $loggedActions[$k] = array_change_key_case($v); + } + $message = ''; + if (!empty($loggedActions[$controller])) { + if (!empty($loggedActions[$controller][$action])) { + $message = $loggedActions[$controller][$action]['message']; + $hit = false; + if (empty($loggedActions[$controller][$action]['role'])) { + $hit = true; + } else { + $role_req = $loggedActions[$controller][$action]['role']; + if (empty($role_req['OR']) && empty($role_req['AND']) && empty($role_req['NOT'])) { + $role_req = array('OR' => $role_req); + } + if (!empty($role_req['NOT'])) { + foreach ($role_req['NOT'] as $k => $v) { + if (!$user['Role'][$v]) { + $hit = true; + continue; + } + } + } + if (!$hit && !empty($role_req['AND'])) { + $subhit = true; + foreach ($role_req['AND'] as $k => $v) { + $subhit = $subhit && $user['Role'][$v]; + } + if ($subhit) { + $hit = true; + } + } + if (!$hit && !empty($role_req['OR'])) { + foreach ($role_req['OR'] as $k => $v) { + if ($user['Role'][$v]) { + $hit = true; + continue; + } + } + } + if ($hit) { + $this->Log = ClassRegistry::init('Log'); + $this->Log->create(); + $this->Log->save(array( + 'org' => 'SYSTEM', + 'model' => 'User', + 'model_id' => $user['id'], + 'email' => $user['email'], + 'action' => 'security', + 'user_id' => $user['id'], + 'title' => __('User triggered security alert by attempting to access /%s/%s. Reason why this endpoint is of interest: %s', $controller, $action, $message), + )); + } + } + } + } + } + + // The check works like this: + // If the user is a site admin, return true + // If the requested action has an OR-d list, iterate through the list. If any of the permissions are set for the user, return true + // If the requested action has an AND-ed list, iterate through the list. If any of the permissions for the user are not set, turn the check to false. Otherwise return true. + // If the requested action has a permission, check if the user's role has it flagged. If yes, return true + // If we fall through all of the checks, return an exception. + public function checkAccess($user, $controller, $action, $soft = false) + { + $controller = lcfirst(Inflector::camelize($controller)); + $action = strtolower($action); + $aclList = $this->__aclList; + foreach ($aclList as $k => $v) { + $aclList[$k] = array_change_key_case($v); + } + $this->__checkLoggedActions($user, $controller, $action); + if ($user['Role']['perm_site_admin']) { + return true; + } + if (!isset($aclList[$controller])) { + return $this->__error(404, 'Invalid controller.', $soft); + } + if ($user['Role']['perm_site_admin']) { + return true; + } + if (isset($aclList[$controller][$action]) && !empty($aclList[$controller][$action])) { + if (in_array('*', $aclList[$controller][$action])) { + return true; + } + if (isset($aclList[$controller][$action]['OR'])) { + foreach ($aclList[$controller][$action]['OR'] as $permission) { + if ($user['Role'][$permission]) { + return true; + } + } + } elseif (isset($aclList[$controller][$action]['AND'])) { + $allConditionsMet = true; + foreach ($aclList[$controller][$action]['AND'] as $permission) { + if (!$user['Role'][$permission]) { + $allConditionsMet = false; + } + } + if ($allConditionsMet) { + return true; + } + } elseif ($user['Role'][$aclList[$controller][$action][0]]) { + return true; + } + } + return $this->__error(403, 'You do not have permission to use this functionality.', $soft); + } + + private function __error($code, $message, $soft = false) + { + if ($soft) { + return $code; + } + switch ($code) { + case 404: + throw new NotFoundException($message); + break; + case 403: + throw new MethodNotAllowedException($message); + default: + throw new InternalErrorException('Unknown error: ' . $message); + } + } + + private function __findAllFunctions() + { + $functionFinder = '/function[\s\n]+(\S+)[\s\n]*\(/'; + $dir = new Folder(APP . 'Controller'); + $files = $dir->find('.*\.php'); + $results = array(); + foreach ($files as $file) { + $controllerName = lcfirst(str_replace('Controller.php', "", $file)); + if ($controllerName === 'app') { + $controllerName = '*'; + } + $functionArray = array(); + $fileContents = file_get_contents(APP . 'Controller' . DS . $file); + $fileContents = preg_replace('/\/\*[^\*]+?\*\//', '', $fileContents); + preg_match_all($functionFinder, $fileContents, $functionArray); + foreach ($functionArray[1] as $function) { + if (substr($function, 0, 1) !== '_' && $function !== 'beforeFilter' && $function !== 'afterFilter') { + $results[$controllerName][] = $function; + } + } + } + return $results; + } + + public function printAllFunctionNames($content = false) + { + $results = $this->__findAllFunctions(); + ksort($results); + return $results; + } + + public function findMissingFunctionNames($content = false) + { + $results = $this->__findAllFunctions(); + $missing = array(); + foreach ($results as $controller => $functions) { + foreach ($functions as $function) { + if (!isset($this->__aclList[$controller]) + || !in_array($function, array_keys($this->__aclList[$controller]))) { + $missing[$controller][] = $function; + } + } + } + return $missing; + } + + public function printRoleAccess($content = false) + { + $results = array(); + $this->Role = ClassRegistry::init('Role'); + $conditions = array(); + if (is_numeric($content)) { + $conditions = array('Role.id' => $content); + } + $roles = $this->Role->find('all', array( + 'recursive' => -1, + 'conditions' => $conditions + )); + if (empty($roles)) { + throw new NotFoundException('Role not found.'); + } + foreach ($roles as $role) { + $urls = $this->__checkRoleAccess($role['Role']); + $results[$role['Role']['id']] = array('name' => $role['Role']['name'], 'urls' => $urls); + } + return $results; + } + + private function __checkRoleAccess($role) + { + $result = array(); + foreach ($this->__aclList as $controller => $actions) { + $controllerNames = Inflector::variable($controller) == Inflector::underscore($controller) ? array(Inflector::variable($controller)) : array(Inflector::variable($controller), Inflector::underscore($controller)); + foreach ($controllerNames as $controllerName) { + foreach ($actions as $action => $permissions) { + if ($role['perm_site_admin']) { + $result[] = DS . $controllerName . DS . $action; + } elseif (in_array('*', $permissions)) { + $result[] = DS . $controllerName . DS . $action . DS . '*'; + } elseif (isset($permissions['OR'])) { + $access = false; + foreach ($permissions['OR'] as $permission) { + if ($role[$permission]) { + $access = true; + } + } + if ($access) { + $result[] = DS . $controllerName . DS . $action . DS . '*'; + } + } elseif (isset($permissions['AND'])) { + $access = true; + foreach ($permissions['AND'] as $permission) { + if ($role[$permission]) { + $access = false; + } + } + if ($access) { + $result[] = DS . $controllerName . DS . $action . DS . '*'; + } + } elseif (isset($permissions[0]) && $role[$permissions[0]]) { + $result[] = DS . $controllerName . DS . $action . DS . '*'; + } + } + } + } + return $result; + } +} diff --git a/app/src/Controller/Component/RestResponseComponent.php b/app/src/Controller/Component/RestResponseComponent.php new file mode 100644 index 0000000..d433358 --- /dev/null +++ b/app/src/Controller/Component/RestResponseComponent.php @@ -0,0 +1,1782 @@ + array( + 'addOrg' => 'add Organisation to', + 'removeOrg' => 'remove Organisation from', + 'addServer' => 'add Server to', + 'removeServer' => 'remove Server from' + ) + ); + + private $___setup = false; + + private $__descriptions = array( + 'Attribute' => array( + 'add' => array( + 'description' => "POST a MISP Attribute JSON to this API to create an Attribute.", + 'mandatory' => array('value', 'type'), + 'optional' => array('category', 'to_ids', 'uuid', 'distribution', 'sharing_group_id', 'timestamp', 'comment', 'data', 'encrypt', 'first_seen', 'last_seen'), + 'params' => array('event_id') + ), + 'edit' => array( + 'description' => "POST a MISP Attribute JSON to this API to update an Attribute. If the timestamp is set, it has to be newer than the existing Attribute.", + 'mandatory' => array(), + 'optional' => array('value', 'type', 'category', 'to_ids', 'uuid', 'distribution', 'sharing_group_id', 'timestamp', 'comment', 'date', 'encrypt', 'first_seen', 'last_seen'), + 'params' => array('attribute_id') + ), + 'deleteSelected' => array( + 'description' => "POST a list of attribute IDs in JSON format to this API to delete the given attributes. This API also expects an event ID passed via the URL or via the event_id key. The id key also takes 'all' as a parameter for a wildcard search to mass delete attributes. If you want the function to also hard-delete already soft-deleted attributes, pass the allow_hard_delete key.", + 'mandatory' => array('id'), + 'optional' => array('event_id', 'allow_hard_delete'), + 'params' => array('event_id') + ), + 'restSearch' => array( + 'description' => "Search MISP using a list of filter parameters and return the data in the selected format. The search is available on an event and an attribute level, just select the scope via the URL (/events/restSearch vs /attributes/restSearch). Besides the parameters listed, other, format specific ones can be passed along (for example: requested_attributes and includeContext for the CSV export). This API allows pagination via the page and limit parameters.", + 'mandatory' => array('returnFormat'), + 'optional' => array('page', 'limit', 'value' , 'type', 'category', 'org', 'tags', 'date', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp', 'timestamp', 'attribute_timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'includeEventTags', 'event_timestamp', 'threat_level_id', 'eventinfo', 'includeProposals', 'includeDecayScore', 'includeFullModel', 'decayingModel', 'excludeDecayed', 'score', 'first_seen', 'last_seen'), + 'params' => array() + ) + ), + 'Community' => array( + 'requestAccess' => array( + 'description' => "POST a request object describing yourself and your organisation to request access to the desired community.", + 'mandatory' => array(), + 'optional' => array('org_name', 'org_uuid', 'sync', 'org_description', 'email', 'message', 'anonymise', 'gpgkey', 'mock'), + 'params' => array('uuid') + ) + ), + 'Event' => array( + 'add' => array( + 'description' => "POST a MISP Event JSON to this API to create an Event. Contained objects can also be included (such as attributes, objects, tags, etc).", + 'mandatory' => array('info'), + 'optional' => array('threat_level_id', 'analysis', 'distribution', 'sharing_group_id', 'uuid', 'published', 'timestamp', 'date', 'Attribute', 'Object', 'Shadow_Attribute', 'EventTag'), + 'params' => array() + ), + 'edit' => array( + 'description' => "POST a MISP Event JSON to this API to update an Event. Contained objects can also be included (such as attributes, objects, tags, etc). If the timestamp is set, it has to be newer than the existing Attribute.", + 'mandatory' => array(), + 'optional' => array('info', 'threat_level_id', 'analysis', 'distribution', 'sharing_group_id', 'uuid', 'published', 'timestamp', 'date', 'Attribute', 'Object', 'Shadow_Attribute', 'EventTag'), + 'params' => array('event_id') + ), + 'index' => array( + 'description' => 'POST a JSON filter object to this API to get the meta-data about matching events.', + 'optional' => array('all', 'attribute', 'published', 'eventid', 'datefrom', 'dateuntil', 'org', 'eventinfo', 'tag', 'tags', 'distribution', 'sharinggroup', 'analysis', 'threatlevel', 'email', 'hasproposal', 'timestamp', 'publishtimestamp', 'publish_timestamp', 'minimal') + ), + 'restSearch' => array( + 'description' => "Search MISP using a list of filter parameters and return the data in the selected format. The search is available on an event and an attribute level, just select the scope via the URL (/events/restSearch vs /attributes/restSearch). Besides the parameters listed, other, format specific ones can be passed along (for example: requested_attributes and includeContext for the CSV export). This API allows pagination via the page and limit parameters.", + 'mandatory' => array('returnFormat'), + 'optional' => array('page', 'limit', 'value', 'type', 'category', 'org', 'tag', 'tags', 'searchall', 'date', 'last', 'eventid', 'withAttachments', 'metadata', 'uuid', 'published', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'sgReferenceOnly', 'eventinfo', 'excludeLocalTags', 'threat_level_id'), + 'params' => array() + ) + ), + 'EventGraph' => array( + 'add' => array( + 'description' => "POST a network in JSON format to this API to to keep an history of it", + 'mandatory' => array('event_id', 'network_json'), + 'optional' => array('network_name') + ) + ), + 'Feed' => array( + 'add' => array( + 'description' => "POST a MISP Feed descriptor JSON to this API to add a Feed.", + 'mandatory' => array('source_format', 'url', 'name', 'input_source', 'provider'), + 'optional' => array('enabled', 'caching_enabled', 'lookup_visible', 'delete_local_file', 'headers', 'fixed_event', 'target_event', 'settings', 'publish', 'override_ids', 'delta_merge', 'distribution', 'sharing_group_id', 'tag_id', 'pull_rules', 'rules', 'event_id'), + 'params' => array() + ), + 'edit' => array( + 'description' => "POST a MISP Feed descriptor JSON to this API to edit a Feed.", + 'mandatory' => array(), + 'optional' => array('source_format', 'url', 'name', 'enabled', 'caching_enabled', 'lookup_visible', 'provider', 'input_source', 'delete_local_file', 'headers', 'fixed_event', 'target_event', 'settings', 'publish', 'override_ids', 'delta_merge', 'distribution', 'sharing_group_id', 'tag_id', 'pull_rules', 'rules', 'event_id'), + 'params' => array('feed_id') + ), + 'previewIndex' => array( + 'description' => 'Sending a GET request to this endpoint will show the parsed feed in JSON format.', + 'mandatory' => array(), + 'optional' => array(), + 'params' => array('feed_id'), + 'http_method' => 'GET' + ) + ), + 'Log' => array( + 'admin_index' => array( + 'description' => "POST a filter object to receive a JSON with the log entries matching the query. A simple get request will return the entire DB. You can use the filter parameters as url parameters with a GET request such as: https://path.to.my.misp/admin/logs/page:1/limit:200 - to run substring queries simply append/prepend/encapsulate the search term with %. All restSearch rules apply.", + "optional" => array('id', 'title', 'created', 'model', 'model_id', 'action', 'user_id', 'change', 'email', 'org', 'description', 'ip') + ), + 'event_index' => array( + 'description' => "Simply run a get request on this endpoint to get the relevant log entries for a given event. This functionality is open to any user having access to a given event." + ) + ), + 'Organisation' => array( + 'admin_add' => array( + 'description' => "POST an Organisation object in JSON format to this API to create a new organsiation.", + 'mandatory' => array('name'), + 'optional' => array('description', 'type', 'nationality', 'sector', 'uuid', 'contacts', 'local') + ), + 'admin_edit' => array( + 'description' => "POST an Organisation object in JSON format to this API to create a new organsiation.", + 'mandatory' => array('name'), + 'optional' => array('description', 'type', 'nationality', 'sector', 'uuid', 'contacts', 'local') + ) + ), + 'Role' => array( + 'admin_add' => array( + 'description' => "POST a Role object in JSON format to this API to create a new role. 'permission' sets the data access permission (0 => read only, 1 => add/edit own, 2 => add/edit org, 3 => publish)", + 'mandatory' => array('name'), + 'optional' => array( + 'perm_delegate', + 'perm_sync', + 'perm_admin', + 'perm_audit', + 'perm_auth', + 'perm_site_admin', + 'perm_regexp_access', + 'perm_tagger', + 'perm_template', + 'perm_sharing_group', + 'perm_tag_editor', + 'default_role', + 'perm_sighting', + 'permission' + ) + ), + 'admin_edit' => array( + 'description' => "POST a Role object in JSON format to this API to edit a role. 'permission' sets the data access permission (0 => read only, 1 => add/edit own, 2 => add/edit org, 3 => publish)", + 'mandatory' => array('name'), + 'optional' => array( + 'perm_delegate', + 'perm_sync', + 'perm_admin', + 'perm_audit', + 'perm_auth', + 'perm_site_admin', + 'perm_regexp_access', + 'perm_tagger', + 'perm_template', + 'perm_sharing_group', + 'perm_tag_editor', + 'default_role', + 'perm_sighting', + 'permission' + ) + ) + ), + 'Server' => array( + 'add' => array( + 'description' => "POST an Server object in JSON format to this API to add a server.", + 'mandatory' => array('url', 'name', 'remote_org_id', 'authkey'), + 'optional' => array('push', 'pull', 'push_sightings', 'push_rules', 'pull_rules', 'submitted_cert', 'submitted_client_cert', 'json') + ), + 'edit' => array( + 'description' => "POST an Server object in JSON format to this API to edit a server.", + 'optional' => array('url', 'name', 'authkey', 'json', 'push', 'pull', 'push_sightings', 'push_rules', 'pull_rules', 'submitted_cert', 'submitted_client_cert', 'remote_org_id') + ), + 'serverSettings' => array( + 'description' => "Send a GET request to this endpoint to get a full diagnostic along with all currently set settings of the current instance. This will also include the worker status" + ) + ), + 'Sighting' => array( + 'add' => array( + 'description' => "POST a simplified sighting object in JSON format to this API to add a or a list of sightings. Pass either value(s) or attribute IDs (can be uuids) to identify the target sightings.", + 'mandatory' => array('OR' => array('values', 'id')), + 'optional' => array('type', 'source', 'timestamp', 'date', 'time') + ), + 'restSearch' => array( + 'description' => "Search MISP sightings using a list of filter parameters and return the data in the JSON format. The search is available on an event, attribute or instance level, just select the scope via the URL (/sighting/restSearch/event vs /sighting/restSearch/attribute vs /sighting/restSearch/). id MUST be provided if context is set.", + 'mandatory' => array('returnFormat'), + 'optional' => array('id', 'type', 'from', 'to', 'last', 'org_id', 'source', 'includeAttribute', 'includeEvent'), + 'params' => array('context') + ), + ), + 'SharingGroup' => array( + 'add' => array( + 'description' => "POST a Sharing Group object in JSON format to this API to add a Sharing Group. The API will also try to capture attached organisations and servers if applicable to the current user.", + 'mandatory' => array('name', 'releasability'), + 'optional' => array('description', 'uuid', 'organisation_uuid', 'active', 'created', 'modified', 'roaming', 'Server' => array('url', 'name', 'all_orgs'), 'Organisation' => array('uuid', 'name', 'extend')) + ), + 'edit' => array( + 'description' => "POST a Sharing Group object in JSON format to this API to edit a Sharing Group. The API will also try to capture attached organisations and servers if applicable to the current user.", + 'mandatory' => array(), + 'optional' => array('name', 'releasability', 'description', 'uuid', 'organisation_uuid', 'active', 'created', 'modified', 'roaming', 'SharingGroupServer' => array('url', 'name', 'all_orgs'), 'SharingGroupOrg' => array('uuid', 'name', 'extend')) + ) + ), + 'Tag' => array( + 'add' => array( + 'description' => "POST a Tag object in JSON format to this API to create a new tag.", + 'mandatory' => array('name'), + 'optional' => array('colour', 'exportable', 'hide_tag', 'org_id', 'user_id') + ), + 'edit' => array( + 'description' => "POST or PUT a Tag object in JSON format to this API to create a edit an existing tag.", + 'optional' => array('name', 'colour', 'exportable', 'hide_tag', 'org_id', 'user_id'), + 'params' => array('tag_id') + ), + 'removeTag' => array( + 'description' => "POST a request object in JSON format to this API to create detach a tag from an event. #FIXME Function does not exists", + 'mandatory' => array('event', 'tag'), + 'params' => array('tag_id') + ), + 'attachTagToObject' => array( + 'description' => "Attach a Tag to an object, refenced by an UUID. Tag can either be a tag id or a tag name.", + 'mandatory' => array('uuid', 'tag'), + ) + ), + 'User' => array( + 'admin_add' => array( + 'description' => "POST a User object in JSON format to this API to create a new user.", + 'mandatory' => array('email', 'org_id', 'role_id'), + 'optional' => array('password', 'external_auth_required', 'external_auth_key', 'enable_password', 'nids_sid', 'server_id', 'gpgkey', 'certif_public', 'autoalert', 'contactalert', 'disabled', 'change_pw', 'termsaccepted', 'newsread') + ), + 'admin_edit' => array( + 'description' => "POST a User object in JSON format to this API to edit a user.", + 'optional' => array('email', 'org_id', 'role_id', 'password', 'external_auth_required', 'external_auth_key', 'enable_password', 'nids_sid', 'server_id', 'gpgkey', 'certif_public', 'autoalert', 'contactalert', 'disabled', 'change_pw', 'termsaccepted', 'newsread') + ), + 'admin_quickEmail' => array( + 'description' => "POST a body and a subject in a JSON to send an e-mail through MISP to the user ID given in the URL", + 'mandatory' => array('subject', 'body') + ), + 'change_pw' => array( + 'description' => "POST a password via a JSON object containing the password key to reset the given user\'s password.", + 'mandatory' => array('password') + ), + 'statistics' => array( + 'description' => 'Simply GET the url endpoint to view the API output of the statistics API. Additional statistics are available via the following tab-options similar to the UI: data, orgs, users, tags, attributehistogram, sightings, attackMatrix', + 'params' => array('tab'), + 'http_method' => 'GET' + ) + ), + 'UserSetting' => array( + 'setSetting' => array( + 'description' => "POST a User setting object in JSON format to this API to create a new setting or update the equivalent existing setting. Admins/site admins can specify a user ID besides their own.", + 'mandatory' => array('setting', 'value'), + 'optional' => array('user_id') + ), + 'delete' => array( + 'description' => "POST or DELETE to this API to delete an existing setting.", + 'params' => array('id') + ) + ), + 'Warninglist' => array( + 'checkValue' => array( + 'description' => "POST a JSON list with value(s) to check against the warninglists to get a JSON dictionary as a response with any hits, if there are any (with the key being the passed value triggering a warning).", + 'mandatory' => array('[]') + ), + 'toggleEnable' => array( + 'description' => "POST a json object with a single or a list of warninglist IDsIDs, or alternatively a (list of) substring(s) that match the names of warninglist(s) to toggle whether they're enabled or disabled. Specify the optional enabled boolean flag if you would like to enforce the outcome state. Not setting this flag will just toggle the current state.",'mandatory' => array('id'), + 'optional' => array('id', 'name', 'enabled') + ) + ) + ); + + private $__scopedFieldsConstraint = array(); + + public function initialize(array $config): void { + $this->__configureFieldConstraints(); + $this->Controller = $this->getController(); + } + + public function getAllApisFieldsConstraint($user) + { + $this->__setup(); + $result = array(); + foreach ($this->__scopedFieldsConstraint as $controller => $actions) { + $controller = Inflector::tableize($controller); + foreach ($actions as $action => $data) { + if ($this->ACL->checkAccess($user, $controller, $action, true) === true) { + $admin_routing = ''; + if (substr($action, 0, 6) === 'admin_') { + $action = substr($action, 6); + $admin_routing = 'admin/'; + } + $url = '/' . $admin_routing . $controller . '/' . $action; + $result[$url] = $data; + } + } + } + return $result; + } + + public function getAllApis($user) + { + $this->__setup(); + $result = array(); + foreach ($this->__descriptions as $controller => $actions) { + $controller = Inflector::tableize($controller); + foreach ($actions as $action => $data) { + if ($this->ACL->checkAccess($user, $controller, $action, true) === true) { + $admin_routing = ''; + if (substr($action, 0, 6) === 'admin_') { + $action = substr($action, 6); + $admin_routing = 'admin/'; + } + $data['api_name'] = '[' . $controller . '] ' . $action; + $data['controller'] = $controller; + $data['action'] = $action; + $data['body'] = array(); + $filter_types = array('mandatory', 'optional'); + foreach ($filter_types as $filter_type) { + if (!empty($data[$filter_type])) { + foreach ($data[$filter_type] as $filter_items) { + if (!is_array($filter_items)) { + $filter_items = array($filter_items); + } + foreach ($filter_items as $filter) { + if ($filter === lcfirst($filter)) { + $data['body'][$filter] = $filter_type; + } else { + $data['body'][$filter] = array($filter_type); + } + } + } + } + } + $data['body'] = json_encode($data['body'], JSON_PRETTY_PRINT); + $url = '/' . $admin_routing . $controller . '/' . $action; + $data['url'] = $url; + if (!empty($data['params'])) { + foreach ($data['params'] as $param) { + $data['url'] .= '/[' . $param . ']'; + } + } + $result[$url] = $data; + } + } + } + return $result; + } + + // use a relative path to check if the current api has a description + public function getApiInfo($relative_path) + { + $this->__setup(); + $relative_path = trim($relative_path, '/'); + $relative_path = explode('/', $relative_path); + $admin = false; + if (count($relative_path) >= 2) { + if ($relative_path[0] == 'admin') { + if (count($relative_path) < 3) { + return '[]'; + } + $admin = true; + $relative_path = array_slice($relative_path, 1); + } + $relative_path[0] = Inflector::camelize(Inflector::singularize($relative_path[0])); + if ($admin) { + $relative_path[1] = 'admin_' . $relative_path[1]; + } + if (isset($this->__descriptions[$relative_path[0]][$relative_path[1]])) { + $temp = $this->__descriptions[$relative_path[0]][$relative_path[1]]; + } else { + $temp = array(); + } + if (empty($temp)) { + return '[]'; + } + return json_encode(array('api_info' => $temp), JSON_PRETTY_PRINT); + } + return '[]'; + } + + public function saveFailResponse($controller, $action, $id = false, $validationErrors, $format = false) + { + $this->autoRender = false; + $response = array(); + $action = $this->__dissectAdminRouting($action); + $stringifiedAction = $action['action']; + if (isset($this->__convertActionToMessage[$controller][$action['action']])) { + $stringifiedAction = $this->__convertActionToMessage[$controller][$action['action']]; + } + $response['saved'] = false; + $response['name'] = 'Could not ' . $stringifiedAction . ' ' . Inflector::singularize($controller); + $response['message'] = $response['name']; + $response['url'] = $this->__generateURL($action, $controller, $id); + $response['errors'] = $validationErrors; + return $this->__sendResponse($response, 403, $format); + } + + public function saveSuccessResponse($controller, $action, $id = false, $format = false, $message = false) + { + $action = $this->__dissectAdminRouting($action); + if (!$message) { + $message = Inflector::singularize($controller) . ' ' . $action['action'] . ((substr($action['action'], -1) == 'e') ? 'd' : 'ed'); + } + $response['saved'] = true; + $response['success'] = true; + $response['name'] = $message; + $response['message'] = $response['name']; + $response['url'] = $this->__generateURL($action, $controller, $id); + return $this->__sendResponse($response, 200, $format); + } + + private function __sendResponse($response, $code, $format = false, $raw = false, $download = false, $headers = array()) + { + if (strtolower($format) === 'application/xml' || strtolower($format) === 'xml') { + if (!$raw) { + if (isset($response[0])) { + if (count(array_keys($response[0])) == 1) { + $key = array_keys($response[0])[0]; + $rearrange = array(); + foreach ($response as $k => $v) { + $rearrange[$key][] = $v[$key]; + } + $response = $rearrange; + } + } + $response = array('response' => $response); + $response = Xml::fromArray($response, array('format' => 'tags')); + $response = $response->asXML(); + } + $type = 'xml'; + } elseif (strtolower($format) == 'openioc') { + $type = 'xml'; + } elseif (strtolower($format) == 'csv') { + $type = 'csv'; + } else { + if (empty($format)) { + $type = 'json'; + } else { + $type = $format; + } + if (!$raw) { + if (is_string($response)) { + $response = array('message' => $response); + } + if (Configure::read('debug') > 1 && !empty($this->Controller->sql_dump)) { + $this->Log = ClassRegistry::init('Log'); + if ($this->Controller->sql_dump === 2) { + $response = array('sql_dump' => $this->Log->getDataSource()->getLog(false, false)); + } else { + $response['sql_dump'] = $this->Log->getDataSource()->getLog(false, false); + } + } + $response = json_encode($response, JSON_PRETTY_PRINT); + } else { + if (Configure::read('debug') > 1 && !empty($this->Controller->sql_dump)) { + $this->Log = ClassRegistry::init('Log'); + if ($this->Controller->sql_dump === 2) { + $response = json_encode(array('sql_dump' => $this->Log->getDataSource()->getLog(false, false))); + } else { + $response = substr_replace( + $response, + sprintf(', "sql_dump": %s}', json_encode($this->Log->getDataSource()->getLog(false, false))), + -2 + ); + } + } + } + } + $cakeResponse = new \Cake\Http\Response(); + $cakeResponse = $cakeResponse->withType($type); + $cakeResponse = $cakeResponse->withStatus($code); + $cakeResponse = $cakeResponse->withStringBody($response); + + if (Configure::read('Security.allow_cors')) { + $headers["Access-Control-Allow-Headers"] = "Origin, Content-Type, Authorization, Accept"; + $headers["Access-Control-Allow-Methods"] = "*"; + $headers["Access-Control-Allow-Origin"] = explode(',', Configure::read('Security.cors_origins')); + $headers["Access-Control-Expose-Headers"] = ["X-Result-Count"]; + } + if (!empty($this->headers)) { + foreach ($this->headers as $key => $value) { + $cakeResponse = $cakeResponse->withHeader($key, $value); + } + } + if (!empty($headers)) { + foreach ($headers as $key => $value) { + $cakeResponse = $cakeResponse->withHeader($key, $value); + } + } + if (!empty($deprecationWarnings)) { + $cakeResponse = $cakeResponse->withHeader('X-Deprecation-Warning', $deprecationWarnings); + } + if ($download) { + $cakeResponse = $cakeResponse->withDownload($download); + } + + return $cakeResponse; + } + + private function __generateURL($action, $controller, $id) + { + $controller = Inflector::underscore(Inflector::pluralize($controller)); + return ($action['admin'] ? '/admin' : '') . '/' . $controller . '/' . $action['action'] . ($id ? '/' . $id : ''); + } + + private function __dissectAdminRouting($action) + { + $admin = false; + if (strlen($action) > 6 && substr($action, 0, 6) == 'admin_') { + $action = substr($action, 6); + $admin = true; + } + return array('action' => $action, 'admin' => $admin); + } + + public function viewData($data, $format = false, $errors = false, $raw = false, $download = false, $headers = array()) + { + if (!empty($errors)) { + $data['errors'] = $errors; + } + return $this->__sendResponse($data, 200, $format, $raw, $download, $headers); + } + + public function sendFile($path, $format = false, $download = false, $name = 'download') + { + $cakeResponse = new \Cake\Http\Response(); + $cakeResponse = $cakeResponse->withStatus = 200; + $cakeResponse = $cakeResponse->withType = $format; + $cakeResponse = $cakeResponse->withDownload($path, array('download' => true, 'name' => $name)); + return $cakeResponse; + } + + public function throwException($code, $message, $url = '', $format = false, $raw = false, $headers = array()) + { + $message = array( + 'name' => $message, + 'message' => $message, + 'url' => $url + ); + return $this->__sendResponse($message, $code, $format, $raw, false, $headers); + } + + public function setHeader($header, $value) + { + $this->headers[$header] = $value; + } + + public function describe($controller, $action, $id = false, $format = false) + { + $this->__setup(); + $actionArray = $this->__dissectAdminRouting($action); + $response['name'] = $this->__generateURL($actionArray, $controller, false) . ' API description'; + $response['description'] = isset($this->__descriptions[Inflector::singularize($controller)][$action]['description']) ? $this->__descriptions[Inflector::singularize($controller)][$action]['description'] : 'This API is not accessible via GET requests.'; + if (isset($this->__descriptions[Inflector::singularize($controller)][$action]['mandatory'])) { + $response['mandatory_fields'] = $this->__descriptions[Inflector::singularize($controller)][$action]['mandatory']; + } + if (isset($this->__descriptions[Inflector::singularize($controller)][$action]['optional'])) { + $response['optional_fields'] = $this->__descriptions[Inflector::singularize($controller)][$action]['optional']; + } + $params = ''; + if (!empty($this->__descriptions[Inflector::singularize($controller)][$action]['params'])) { + foreach ($this->__descriptions[Inflector::singularize($controller)][$action]['params'] as $k => $param) { + $params .= ($k > 0 ? '/': '') . '[' . $param . ']'; + } + } + $response['url'] = $this->__generateURL($actionArray, $controller, $params); + return $this->__sendResponse($response, 200, $format); + } + + private function __setup() + { + if (!$this->__setup) { + $scopes = array('Event', 'Attribute', 'Sighting'); + foreach ($scopes as $scope) { + $this->{$scope} = ClassRegistry::init($scope); + $this->__descriptions[$scope]['restSearch'] = array( + 'description' => $this->__descriptions[$scope]['restSearch']['description'], + 'returnFormat' => array_keys($this->{$scope}->validFormats), + 'mandatory' => $this->__descriptions[$scope]['restSearch']['mandatory'], + 'optional' => $this->__descriptions[$scope]['restSearch']['optional'], + 'params' => $this->__descriptions[$scope]['restSearch']['params'] + ); + } + $this->__setupFieldsConstraint(); + } + return true; + } + + private $__fieldConstraint = array(); + + // default value and input for API field + private function __configureFieldConstraints() + { + $this->__fieldsConstraint = array( + 'action' => array( + 'input' => 'select', + 'type' => 'string', + 'operators' => array('equal'), + 'values' => array('action1'), + 'help' => __('The action that the user performed') + ), + 'active' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Is the sharing group selectable (active) when chosing distribution') + ), + 'all' => array( + 'input' => 'text', + 'type' => 'string', + 'help' => __('Search for a full or a substring (delimited by % for substrings) in the event info, event tags, attribute tags, attribute values or attribute comment fields') + ), + 'all_orgs' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('All organisations contained on the instance will be part of the sharing group') + ), + 'allow_hard_delete' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('hard-delete already soft-deleted attributes') + ), + 'analysis' => array( + 'input' => 'select', + 'type' => 'integer', + 'operators' => array('equal', 'not_equal'), + 'values' => array( 0 => 'Initial', 1 => 'Ongoing', 2 => 'Completed'), + 'help' => __('Maturity of the event') + ), + 'anonymise' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'operators' => array('equal'), + 'help' => __('Anonymise the information regarding the server on which the request was issued') + ), + 'attribute' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Filter on attribute value') + ), + 'authkey' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('The authorisation key found on the external server') + ), + 'autoalert' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('The user receive alerts when events are published') + ), + 'body' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('The email\'s body') + ), + 'caching_enabled' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('The feed is cached') + ), + 'category' => array( + 'input' => 'select', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + 'values' => array('categ1'), + ), + 'certif_public' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('A valid x509 certificate ') + ), + 'change' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('The text contained in the change field') + ), + 'change_pw' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('The user will be prompted the change the password') + ), + 'colour' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('A valid hexadecimal colour `#ffffff`') + ), + 'comment' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal', 'not_equal') + ), + 'contacts' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Contact details for the organisation') + ), + 'contactalert' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('The user receive alerts from `contact reporter` requests') + ), + 'created' => array( + 'type' => 'date', + 'validation' => array( 'format' => 'YYYY-MM-DD' ), + 'plugin' => 'datepicker', + 'plugin_config' => array( + 'format' => 'yyyy/mm/dd', + 'todayBtn' => 'linked', + 'todayHighlight' => true, + 'autoclose' => true + ), + ), + 'data' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Base64 encoded file contents') + ), + 'date' => array( + 'type' => 'date', + 'validation' => array( 'format' => 'YYYY-MM-DD' ), + 'plugin' => 'datepicker', + 'plugin_config' => array( + 'format' => 'yyyy/mm/dd', + 'todayBtn' => 'linked', + 'todayHighlight' => true, + 'autoclose' => true + ), + 'help' => __('The user set date field on the event level. If you are using restSearch, you can use any of the valid time related filters (examples: 7d, timestamps, [14d, 7d] for ranges, etc.)') + ), + 'datefrom' => array( + 'type' => 'date', + 'validation' => array( 'format' => 'YYYY-MM-DD' ), + 'plugin' => 'datepicker', + 'plugin_config' => array( + 'format' => 'yyyy/mm/dd', + 'todayBtn' => 'linked', + 'todayHighlight' => true, + 'autoclose' => true + ), + ), + 'dateuntil' => array( + 'type' => 'date', + 'validation' => array( 'format' => 'YYYY-MM-DD' ), + 'plugin' => 'datepicker', + 'plugin_config' => array( + 'format' => 'yyyy/mm/dd', + 'todayBtn' => 'linked', + 'todayHighlight' => true, + 'autoclose' => true + ), + ), + 'decayingModel' => array( + 'input' => 'select', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + 'unique' => true, + 'help' => 'Specify the decaying model from which the decaying score should be calculated' + ), + 'default_role' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('The role is a default role (selected by default)') + ), + 'delete_local_file' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Remove file after ingestion') + ), + 'deleted' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Include deleted elements') + ), + 'delta_merge' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Merge attributes (only add new attribute, remove revoked attributes)') + ), + 'description' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + ), + 'disabled' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Disable the user account') + ), + 'distribution' => array( + 'input' => 'select', + 'type' => 'integer', + 'operators' => ['equal', 'not_equal'], + 'values' => array(0 => 'dist1'), + ), + 'email' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + 'help' => __('Filter on user email') + ), + 'enable_password' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Set the password manually') + ), + 'enabled' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + 'encrypt' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('When uploading malicious samples, set this flag to tell MISP to encrpyt the sample and extract the file hashes. This will create a MISP object with the appropriate attributes.') + ), + //'enforceWarningList' => array( + // 'input' => 'radio', + // 'type' => 'integer', + // 'values' => array(1 => 'True', 0 => 'False' ) + //), + 'enforceWarninglist' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Should the warning list be enforced. Adds `blocked` field for matching attributes') + ), + 'event_id' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal', 'not_equal'), + 'validation' => array('min' => 0, 'step' => 1) + ), + 'event_timestamp' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal', 'not_equal'), + 'validation' => array('min' => 0, 'step' => 1), + 'help' => __('The timestamp at which the event was last modified') + ), + 'attribute_timestamp' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal', 'not_equal'), + 'validation' => array('min' => 0, 'step' => 1), + 'help' => __('The timestamp at which the attribute was last modified') + ), + 'eventid' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal', 'not_equal'), + 'validation' => array('min' => 0, 'step' => 1) + ), + 'eventinfo' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + 'help' => __('Quick event description') + ), + 'exportable' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('The tag is exported when synchronising with other instances') + ), + 'excludeDecayed' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => 'Should the decayed elements by excluded' + ), + 'excludeLocalTags' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Exclude local tags from the export') + ), + 'extend' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('The organisation have write access to this sharing group (they can add/remove other organisation)') + ), + 'external_auth_required' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('An external authorisation is required for this user') + ), + 'external_auth_key' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('A valid external auth key') + ), + 'first_seen' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => 'A valid ISO 8601 datetime format, up to milli-seconds. i.e.: 2019-06-13T15:56:56.856074+02:00' + ), + 'fixed_event' => array( + 'input' => 'select', + 'type' => 'integer', + 'operators' => array('equal'), + 'values' => array( 0 => 'New Event Each Pull', 1 => 'Fixed Event'), + 'help' => __('target_event option might be considered') + ), + 'from' => array( + 'type' => 'date', + 'validation' => array( 'format' => 'YYYY-MM-DD' ), + 'plugin' => 'datepicker', + 'plugin_config' => array( + 'format' => 'yyyy/mm/dd', + 'todayBtn' => 'linked', + 'todayHighlight' => true, + 'autoclose' => true + ), + 'help' => __('The date from which the event was published') + ), + 'gpgkey' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('A valid GPG key') + ), + 'hasproposal' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('The event contains proposals') + ), + 'headers' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Headers to be passed with the requests. All separated by `\n`') + ), + 'hide_tag' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('The tag is hidden (not selectable)') + ), + 'id' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal', 'not_equal'), + 'validation' => array('min' => 0, 'step' => 1) + ), + 'includeAttribute' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Include matching attributes in the response') + ), + 'includeDecayScore' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => 'Include all enabled decaying score' + ), + 'includeEvent' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Include matching events in the response') + ), + 'includeEventUuid' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Include matching eventUuids in the response') + ), + 'includeEventTags' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Include tags of matching events in the response') + ), + 'includeFullModel' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => 'Include all model information of matching events in the response' + ), + 'includeProposals' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Include proposals of matching events in the response') + ), + 'info' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + 'help' => __('Quick event description') + ), + 'input_source' => array( + 'input' => 'select', + 'type' => 'string', + 'operators' => array('equal'), + 'values' => array( 'network' => 'Network', 'local' => 'Local'), + 'help' => __('Specify whether the source (url field) is a directory (local) or an geniun url (network)') + ), + 'ip' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('The IP of a login attempt') + ), + 'json' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('JSON containing ID, UUID and name') + ), + 'last' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + 'help' => __('Events published within the last x amount of time, where x can be defined in days, hours, minutes (for example 5d or 12h or 30m)') + ), + 'last_seen' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => 'A valid ISO 8601 datetime format, up to milli-seconds. i.e.: 2019-06-13T15:56:56.856074+02:00' + ), + 'limit' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal'), + 'validation' => array('min' => 0, 'step' => 1), + 'help' => __('Limit on the pagination') + ), + 'local' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('If the organisation should have access to this instance, make sure that the Local organisation setting is checked. If you would only like to add a known external organisation for inclusion in sharing groups, uncheck the Local organisation setting.') + ), + 'lookup_visible' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('The lookup will not be visible in the feed correlation') + ), + 'message' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + 'help' => __('Message to be included') + ), + 'metadata' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Will only return the metadata of the given query scope, contained data is omitted.') + ), + 'minimal' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Will only return id, timestamp, published and uuid') + ), + 'mock' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'operators' => array('equal'), + 'help' => __('Mock the query') + ), + 'model' => array( + 'input' => 'select', + 'type' => 'string', + 'operators' => array('equal'), + 'values' => array('Attribute', 'Event', 'EventBlacklist', 'EventTag', 'MispObject', 'Organisation', 'Post', 'Regexp', 'Role', 'Server', 'ShadowAttribute', 'SharingGroup', 'Tag', 'Task', 'Taxonomy', 'Template', 'Thread', 'User', 'Whitelist'), + ), + 'model_id' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal'), + 'validation' => array('min' => 0, 'step' => 1), + ), + 'modified' => array( + 'type' => 'date', + 'validation' => array( 'format' => 'YYYY-MM-DD' ), + 'plugin' => 'datepicker', + 'plugin_config' => array( + 'format' => 'yyyy/mm/dd', + 'todayBtn' => 'linked', + 'todayHighlight' => true, + 'autoclose' => true + ), + 'help' => __('The last time the sharing group was modified') + ), + 'name' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + ), + 'nationality' => array( + 'input' => 'select', + 'type' => 'string', + 'operators' => array('equal'), + 'values' => array('nat1'), + ), + 'newsread' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal'), + 'validation' => array('min' => 0, 'step' => 1), + 'help' => __('The news are read') + ), + 'nids_sid' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal'), + 'validation' => array('min' => 0, 'step' => 1), + 'help' => __('The unique Signature Identification') + ), + 'org' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + 'help' => __('Can be either the ORG_ID or the ORG_NAME') + ), + 'org_description' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + 'help' => __('Describe the organisation') + ), + 'org_name' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + 'help' => __('Organisation identifier (name)') + ), + 'org_id' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal'), + 'validation' => array('min' => 0, 'step' => 1), + ), + 'org_uuid' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Globally used uuid of an organisation') + ), + 'organisation_uuid' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Globally used uuid of an organisation') + ), + 'override_ids' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('The IDS flags will be set to off for this feed') + ), + 'page' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal'), + 'validation' => array('min' => 1, 'step' => 1), + 'help' => __('Page number for the pagination') + ), + 'password' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('The hardcoded password') + ), + 'perm_admin' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + 'perm_audit' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + 'perm_auth' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + 'perm_delegate' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + 'perm_regexp_access' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + 'perm_sharing_group' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + 'perm_sighting' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + 'perm_site_admin' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + 'perm_sync' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + 'perm_tag_editor' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + 'perm_tagger' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + 'perm_template' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + 'permission' => array( + 'input' => 'select', + 'type' => 'string', + 'operators' => array('equal'), + 'values' => array(0 =>'Read Only', 1 => 'Manage Own Events', 2 => 'Manage Organisation Events', 3 => 'Manage and Publish Organisation Events'), + ), + 'provider' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + 'help' => __('The name of the feed provider') + ), + 'publish' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('The event will be published') + ), + 'publish_timestamp' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal', 'not_equal'), + 'validation' => array('min' => 0, 'step' => 1) + ), + 'published' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + 'publishtimestamp' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal', 'not_equal'), + 'validation' => array('min' => 0, 'step' => 1) + ), + 'pull' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Allow the download of events and their attribute from the server') + ), + 'push' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Allow the upload of events and their attribute to the server') + ), + 'push_sightings' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Allow the upload of sightings to the server') + ), + 'releasability' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Concise summary for who this sharing group is releasable to') + ), + 'remote_org_id' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal'), + 'validation' => array('min' => 0, 'step' => 1), + ), + 'returnFormat' => array( + 'input' => 'select', + 'type' => 'string', + 'operators' => array('equal'), + 'values' => array('json', 'openioc', 'xml', 'suricata', 'snort', 'text', 'rpz', 'csv', 'cache', 'stix', 'stix2'), + ), + 'roaming' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Pass the event to any connected instance where the sync connection is tied to an organisation contained in the SG organisation list') + ), + 'role_id' => array( + 'input' => 'select', + 'type' => 'integer', + 'operators' => array('equal'), + 'validation' => array(0 => 'role1'), + ), + 'score' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal'), + 'validation' => array('min' => 0, 'step' => 1, 'max' => 100), + 'help' => 'An alias to override on-the-fly the threshold of the decaying model' + ), + 'searchall' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Search for a full or a substring (delimited by % for substrings) in the event info, event tags, attribute tags, attribute values or attribute comment fields') + ), + 'sector' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('The sector of the organisation') + ), + 'server_id' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal'), + 'validation' => array('min' => 0, 'step' => 1), + ), + 'sgReferenceOnly' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'help' => __('Will only return the sharing group ID') + ), + 'sharing_group_id' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal', 'not_equal'), + 'validation' => array('min' => 0, 'step' => 1) + ), + 'sharinggroup' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal', 'not_equal'), + 'validation' => array('min' => 0, 'step' => 1), + 'help' => __('Sharing group ID') + ), + 'source' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('The source of the Sighting (e.g. honeypot_1)') + ), + 'source_format' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'values' => array( 'misp' => 'MISP Feed', 'freetext' => 'Freetext Parsed Feed', 'csv' => 'CSV Parsed Feed') + ), + 'subject' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('The email\'s subject') + ), + 'submitted_cert' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Base64 encoded certificate') + ), + 'submitted_client_cert' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Base64 encoded certificate') + ), + 'sync' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ), + 'operators' => array('equal') + ), + 'tag' => array( + 'input' => 'select', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + ), + 'tag_id' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal'), + 'validation' => array('min' => 0, 'step' => 1), + 'help' => __('A tad ID to attach to created events') + ), + 'tags' => array( + 'input' => 'select', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + 'unique' => false, + ), + 'target_event' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal'), + 'validation' => array('min' => 0, 'step' => 1), + 'help' => __('The provided ID will be reused as an existing event') + ), + 'termsaccepted' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + 'threat_level_id' => array( + 'input' => 'select', + 'type' => 'integer', + 'operators' => ['equal', 'not_equal'], + 'values' => array( 1 => 'High', 2 => 'Medium', 3 => 'Low', 4 => 'Undefined') + ), + 'threatlevel' => array( + 'input' => 'select', + 'type' => 'integer', + 'operators' => ['equal', 'not_equal'], + 'values' => array( 1 => 'High', 2 => 'Medium', 3 => 'Low', 4 => 'Undefined') + ), + 'time' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Time of the sighting with the form `h:i:s`') + ), + 'timestamp' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal', 'not_equal'), + 'validation' => array('min' => 0, 'step' => 1) + ), + 'title' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('The title of the log') + ), + 'to' => array( + 'type' => 'date', + 'validation' => array( 'format' => 'YYYY-MM-DD' ), + 'plugin' => 'datepicker', + 'plugin_config' => array( + 'format' => 'yyyy/mm/dd', + 'todayBtn' => 'linked', + 'todayHighlight' => true, + 'autoclose' => true + ), + 'help' => __('The date to which the event was published') + ), + 'to_ids' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False'), + 'help' => __('The state of the `to_ids` flag') + ), + 'type' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + 'help' => __('The type of the attribute') + ), + 'url' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal', 'not_equal'), + ), + 'user_id' => array( + 'input' => 'number', + 'type' => 'integer', + 'operators' => array('equal'), + 'validation' => array('min' => 0, 'step' => 1), + ), + 'uuid' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal', 'not_equal') + ), + 'value' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal', 'not_equal') + ), + 'values' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'unique' => false, + 'help' => __('Placeholder containing values to sight') + ), + 'withAttachments' => array( + 'input' => 'radio', + 'type' => 'integer', + 'values' => array(1 => 'True', 0 => 'False' ) + ), + + // Not supported yet + '[]' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Not supported (warninglist->checkvalues) expect an array') + ), + 'event' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Not supported (removeTag)') + ), + 'push_rules' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Not supported') + ), + 'pull_rules' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Not supported') + ), + 'rules' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Not supported') + ), + + 'settings' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Not supported') + ), + 'network_name' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Not supported') + ), + 'network_json' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Not supported') + ), + 'Attribute' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Not supported') + ), + 'Object' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Not supported') + ), + 'EventTag' => array( + 'input' => 'select', + 'type' => 'string', + 'operators' => array('equal'), + ), + 'Shadow_Attribute' => array( + 'input' => 'text', + 'type' => 'string', + 'operators' => array('equal'), + 'help' => __('Not supported') + ), + ); + } + + // create dictionnary mapping between fields constraints and scope->action + private function __setupFieldsConstraint() { + foreach ($this->__descriptions as $scope => $desc) { + foreach ($desc as $action => $params) { + $fieldsConstraint = array(); + foreach ($params as $paramType => $field) { + if ($paramType == 'optional' || $paramType == 'mandatory') { + $fields = array_values($field); + if (!empty($fields)) { + foreach($fields as $field) { + if (is_array($field)) { + foreach($field as $sf) { + $fieldsConstraint[$sf] = $this->__fieldsConstraint[$sf]; + $label = $scope . '.' . $sf; + $fieldsConstraint[$sf]['id'] = $label; + $fieldsConstraint[$sf]['label'] = $label; + } + } else { + if (!empty($this->__fieldsConstraint[$field])) { + $fieldsConstraint[$field] = $this->__fieldsConstraint[$field]; + $label = $scope . '.' . $field; + $fieldsConstraint[$field]['id'] = $label; + $fieldsConstraint[$field]['label'] = $label; + } + } + + // add dynamic data and overwrite name collisions + switch($field) { + case "returnFormat": + $this->__overwriteReturnFormat($scope, $action, $fieldsConstraint[$field]); + break; + case "type": + $this->__overwriteType($scope, $action, $fieldsConstraint[$field]); + break; + case "category": + $this->__overwriteCategory($scope, $action, $fieldsConstraint[$field]); + break; + case "decayingModel": + $this->__overwriteDecayingModel($scope, $fieldsConstraint[$field]); + break; + case "distribution": + $this->__overwriteDistribution($scope, $action, $fieldsConstraint[$field]); + break; + case "tag": + case "tags": + case "EventTag": + $this->__overwriteTags($scope, $action, $fieldsConstraint[$field]); + break; + case "nationality": + $this->__overwriteNationality($scope, $action, $fieldsConstraint[$field]); + break; + case "action": + $this->__overwriteAction($scope, $action, $fieldsConstraint[$field]); + break; + case "role_id": + $this->__overwriteRoleId($scope, $action, $fieldsConstraint[$field]); + break; + case "first_seen": + case "last_seen": + $this->__overwriteSeen($scope, $action, $fieldsConstraint[$field]); + break; + default: + break; + } + + } + } + } + } + $this->__scopedFieldsConstraint[$scope][$action] = $fieldsConstraint; + } + } + } + + // Fetch the correct values based on the scope, then overwrite default value + private function __overwriteReturnFormat($scope, $action, &$field) { + switch($scope) { + case "Attribute": + $field['values'] = array_keys(ClassRegistry::init($scope)->validFormats); + break; + case "Event": + $field['values'] = array_keys(ClassRegistry::init($scope)->validFormats); + break; + } + } + private function __overwriteType($scope, $action, &$field) { + $field['input'] = 'select'; + switch($scope) { + case "Attribute": + $field['values'] = array_keys(ClassRegistry::init($scope)->typeDefinitions); + break; + case "Event": + $field['values'] = array_keys(ClassRegistry::init("Attribute")->typeDefinitions); + break; + case "Sighting": + $field['values'] = ClassRegistry::init($scope)->type; + break; + default: + $field['input'] = 'text'; + break; + } + } + + private function __overwriteCategory($scope, $action, &$field) { + $field['values'] = array_keys(ClassRegistry::init("Attribute")->categoryDefinitions); + } + private function __overwriteDistribution($scope, $action, &$field) { + $field['values'] = array(); + foreach(ClassRegistry::init("Attribute")->distributionLevels as $d => $text) { + $field['values'][] = array('label' => $text, 'value' => $d); + } + } + private function __overwriteDecayingModel($scope, &$field) { + $this->{$scope} = ClassRegistry::init("DecayingModel"); + $models = $this->{$scope}->find('list', array( + 'recursive' => -1, + 'fields' => array('name') + )); + $field['values'] = array(); + foreach($models as $i => $model_name) { + $field['values'][] = array('label' => h($model_name), 'value' => $i); + } + } + private function __overwriteTags($scope, $action, &$field) { + $this->{$scope} = ClassRegistry::init("Tag"); + $tags = $this->{$scope}->find('list', array( + 'recursive' => -1, + 'fields' => array('name') + )); + foreach($tags as $i => $tag) { + $tagname = htmlspecialchars($tag); + $tags[$tagname] = $tagname; + unset($tags[$i]); + } + $field['values'] = $tags; + } + private function __overwriteNationality($scope, $action, &$field) { + $field['values'] = ClassRegistry::init("Organisation")->countries; + } + private function __overwriteAction($scope, $action, &$field) { + $field['values'] = array_keys(ClassRegistry::init("Log")->actionDefinitions); + } + private function __overwriteRoleId($scope, $action, &$field) { + $this->{$scope} = ClassRegistry::init("Role"); + $roles = $this->{$scope}->find('list', array( + 'recursive' => -1, + 'fields' => array('name') + )); + $field['values'] = $roles; + } + private function __overwriteSeen($scope, $action, &$field) { + if ($action == 'restSearch') { + $field['help'] = __('Seen within the last x amount of time, where x can be defined in days, hours, minutes (for example 5d or 12h or 30m)'); + } + } + +} diff --git a/app/src/Controller/EncryptionKeysController.php b/app/src/Controller/EncryptionKeysController.php new file mode 100644 index 0000000..412c117 --- /dev/null +++ b/app/src/Controller/EncryptionKeysController.php @@ -0,0 +1,117 @@ +EncryptionKeys->find(); + if (!empty($owner_type)) { + $query->where(['owner_type' => $owner_type]); + } + if (!empty($owner_id)) { + $query->where(['owner_id' => $owner_id]); + } + if ($this->_isRest()) { + $alignments = $query->all(); + return $this->RestResponse->viewData($alignments, 'json'); + } else { + $this->loadComponent('Paginator'); + $encrpyion_keys = $this->Paginator->paginate($query); + $this->set('data', $encrpyion_keys); + $this->set('metaGroup', 'ContactDB'); + } + } + + public function delete($id) + { + if (empty($id)) { + throw new NotFoundException(__('Invalid encrpyion keys.')); + } + $individual = $this->Alignments->get($id); + if ($this->request->is('post') || $this->request->is('delete')) { + if ($this->Alignments->delete($individual)) { + $message = __('Individual deleted.'); + if ($this->_isRest()) { + $individual = $this->Alignments->get($id); + return $this->RestResponse->saveSuccessResponse('Alignments', 'delete', $id, 'json', $message); + } else { + $this->Flash->success($message); + return $this->redirect($this->referer()); + } + } + } + $this->set('metaGroup', 'ContactDB'); + $this->set('scope', 'alignments'); + $this->set('id', $individual['id']); + $this->set('alignment', $individual); + $this->viewBuilder()->setLayout('ajax'); + $this->render('/genericTemplates/delete'); + } + + public function add($owner_type = false, $owner_id = false) + { + if (empty($owner_type) && !empty($this->request->getData('owner_type'))) { + $owner_type = $this->request->getData('owner_type'); + } + if (empty($owner_id) && !empty($this->request->getData('owner_id'))) { + $owner_id = $this->request->getData('owner_id'); + } + if (empty($owner_type) || empty($owner_id)) { + throw new NotAcceptableException(__('Invalid input. owner_type and owner_id expected as parameters in the format /encryption_keys/add/[owner_type]/[owner_id] or passed as a JSON.')); + } + if ($owner_type === 'individual') { + $this->loadModel('Individuals'); + $owner = $this->Individuals->find()->where(['id' => $owner_id])->first(); + if (empty($owner)) { + throw new NotFoundException(__('Invalid owner individual.')); + } + } else { + $this->loadModel('Organisations'); + $owner = $this->Organisations->find()->where(['id' => $owner_id])->first(); + if (empty($owner)) { + throw new NotFoundException(__('Invalid owner individual.')); + } + } + $encryptionKey = $this->EncryptionKeys->newEmptyEntity(); + if ($this->request->is('post')) { + $this->EncryptionKeys->patchEntity($encryptionKey, $this->request->getData()); + $encrypionKey['owner_type'] = $owner_type; + if ($this->EncryptionKeys->save($encryptionKey)) { + $message = __('EncryptionKey added.'); + if ($this->_isRest()) { + $encryptionKey = $this->EncryptionKeys->get($this->EncryptionKeys->id); + return $this->RestResponse->viewData($encryptionKey, 'json'); + } else { + $this->Flash->success($message); + $this->redirect($this->referer()); + } + } else { + $message = __('EncryptionKey could not be added.'); + if ($this->_isRest()) { + return $this->RestResponse->saveFailResponse('EncryptionKeys', 'add', false, $message); + } else { + $this->Flash->error($message); + $this->redirect($this->referer()); + } + } + } + + $this->set(compact('owner')); + $this->set(compact('encryptionKey')); + $this->set(compact('owner_id')); + $this->set(compact('owner_type')); + $this->set('metaGroup', 'ContactDB'); + } +} diff --git a/app/src/Controller/ErrorController.php b/app/src/Controller/ErrorController.php new file mode 100644 index 0000000..27dfde5 --- /dev/null +++ b/app/src/Controller/ErrorController.php @@ -0,0 +1,70 @@ +loadComponent('RequestHandler'); + } + + /** + * beforeFilter callback. + * + * @param \Cake\Event\EventInterface $event Event. + * @return \Cake\Http\Response|null|void + */ + public function beforeFilter(EventInterface $event) + { + } + + /** + * beforeRender callback. + * + * @param \Cake\Event\EventInterface $event Event. + * @return \Cake\Http\Response|null|void + */ + public function beforeRender(EventInterface $event) + { + parent::beforeRender($event); + + $this->viewBuilder()->setTemplatePath('Error'); + } + + /** + * afterFilter callback. + * + * @param \Cake\Event\EventInterface $event Event. + * @return \Cake\Http\Response|null|void + */ + public function afterFilter(EventInterface $event) + { + } +} diff --git a/app/src/Controller/IndividualsController.php b/app/src/Controller/IndividualsController.php new file mode 100644 index 0000000..ed87702 --- /dev/null +++ b/app/src/Controller/IndividualsController.php @@ -0,0 +1,155 @@ +Individuals->find(); + $filterFields = ['uuid', 'email', 'first_name', 'last_name', 'position']; + if (!empty($this->request->getQuery('quickFilter'))) { + $quickFilter = $this->request->getQuery('quickFilter'); + $conditions = []; + foreach ($filterFields as $field) { + $conditions[] = [$field . ' LIKE' => '%' . $quickFilter . '%']; + } + } + $quickFilter = $this->request->getQuery('quickFilter'); + foreach ($filterFields as $filterField) { + $tempFilter = $this->request->getQuery($filterField); + if (!empty($tempFilter)) { + if (strpos($tempFilter, '%') !== false) { + $conditions[] = [$filterField . ' LIKE' => $tempFilter]; + } else { + $conditions[] = [$filterField => $tempFilter]; + } + } + } + $query->contain(['Alignments' => 'Organisations']); + if (!empty($this->request->getQuery('organisation_id'))) { + $query->matching('Alignments', function($q) { + return $q->where(['Alignments.organisation_id' => $this->request->getQuery('organisation_id')]); + }); + } + if (!empty($conditions)) { + $query->where($conditions); + } + if ($this->_isRest()) { + $individuals = $query->all(); + return $this->RestResponse->viewData($individuals, 'json'); + } else { + $this->loadComponent('Paginator'); + $individuals = $this->Paginator->paginate($query); + $this->set('data', $individuals); + $this->set('alignmentScope', 'individuals'); + $this->set('metaGroup', 'ContactDB'); + } + } + + public function add() + { + $individual = $this->Individuals->newEmptyEntity(); + if ($this->request->is('post')) { + $individual = $this->Individuals->patchEntity($individual, $this->request->getData()); + if ($this->Individuals->save($individual)) { + $message = __('Individual added.'); + if ($this->_isRest()) { + $individual = $this->Individuals->get($id); + return $this->RestResponse->viewData($individual, 'json'); + } else { + $this->Flash->success($message); + $this->redirect(['action' => 'index']); + } + } else { + $message = __('Individual could not be added.'); + if ($this->_isRest()) { + + } else { + $this->Flash->error($message); + } + } + } + $this->set('metaGroup', 'ContactDB'); + $this->set('individual', $individual); + } + + public function view($id) + { + if (empty($id)) { + throw new NotFoundException(__('Invalid organisation.')); + } + $individual = $this->Individuals->get($id, [ + 'contain' => ['Alignments' => 'Organisations'] + ]); + if ($this->_isRest()) { + return $this->RestResponse->viewData($individual, 'json'); + } else { + + } + $this->set('metaGroup', 'ContactDB'); + $this->set('individual', $individual); + } + + public function edit($id) + { + if (empty($id)) { + throw new NotFoundException(__('Invalid organisation.')); + } + $individual = $this->Individuals->get($id); + if ($this->request->is(['post', 'put'])) { + $this->Individuals->patchEntity($individual, $this->request->getData()); + if ($this->Individuals->save($individual)) { + $message = __('Individual updated.'); + if ($this->_isRest()) { + $individual = $this->Individuals->get($id); + return $this->RestResponse->viewData($individual, 'json'); + } else { + $this->Flash->success($message); + return $this->redirect(['action' => 'index']); + } + } else { + if ($this->_isRest()) { + + } + } + } + $this->set('metaGroup', 'ContactDB'); + $this->set('individual', $individual); + $this->render('add'); + } + + public function delete($id) + { + if (empty($id)) { + throw new NotFoundException(__('Invalid organisation.')); + } + $individual = $this->Individuals->get($id); + if ($this->request->is('post') || $this->request->is('delete')) { + if ($this->Individuals->delete($individual)) { + $message = __('Individual deleted.'); + if ($this->_isRest()) { + $individual = $this->Individuals->get($id); + return $this->RestResponse->saveSuccessResponse('Individuals', 'delete', $id, 'json', $message); + } else { + $this->Flash->success($message); + return $this->redirect($this->referer()); + } + } + } + $this->set('metaGroup', 'ContactDB'); + $this->set('scope', 'individuals'); + $this->set('id', $individual['id']); + $this->set('individual', $individual); + $this->viewBuilder()->setLayout('ajax'); + $this->render('/genericTemplates/delete'); + } +} diff --git a/app/src/Controller/OrganisationsController.php b/app/src/Controller/OrganisationsController.php new file mode 100644 index 0000000..f7704ca --- /dev/null +++ b/app/src/Controller/OrganisationsController.php @@ -0,0 +1,153 @@ +request->getQuery('quickFilter'))) { + $quickFilter = $this->request->getQuery('quickFilter'); + $conditions = []; + foreach ($filterFields as $field) { + $conditions[] = [$field . ' LIKE' => '%' . $quickFilter . '%']; + } + } + $quickFilter = $this->request->getQuery('quickFilter'); + foreach ($filterFields as $filterField) { + $tempFilter = $this->request->getQuery($filterField); + if (!empty($tempFilter)) { + if (strpos($tempFilter, '%') !== false) { + $conditions[] = [$filterField . ' LIKE' => $tempFilter]; + } else { + $conditions[] = [$filterField => $tempFilter]; + } + } + } + $query = $this->Organisations->find(); + $query->contain(['Alignments' => 'Individuals']); + if (!empty($this->request->getQuery('individual_id'))) { + $query->matching('Alignments', function($q) { + return $q->where(['Alignments.individual_id' => $this->request->getQuery('individual_id')]); + }); + } + if (!empty($conditions)) { + $query->where([ + 'OR' => $conditions + ]); + } + if ($this->_isRest()) { + $organisations = $query->all(); + return $this->RestResponse->viewData($organisations, 'json'); + } else { + $this->loadComponent('Paginator'); + $organisations = $this->Paginator->paginate($query); + $this->set('data', $organisations); + $this->set('metaGroup', 'ContactDB'); + } + } + + public function add() + { + $organisation = $this->Organisations->newEmptyEntity(); + if ($this->request->is('post')) { + $organisation = $this->Organisations->patchEntity($organisation, $this->request->getData()); + if ($this->Organisations->save($organisation)) { + $message = __('Organisation added.'); + if ($this->_isRest()) { + $organisation = $this->Organisations->get($id); + return $this->RestResponse->viewData($organisation, 'json'); + } else { + $this->Flash->success($message); + $this->redirect(['action' => 'index']); + } + } else { + $message = __('Organisation could not be added.'); + if ($this->_isRest()) { + + } else { + $this->Flash->error($message); + } + } + } + $this->set('metaGroup', 'ContactDB'); + $this->set('organisation', $organisation); + } + + public function view($id) + { + if (empty($id)) { + throw new NotFoundException(__('Invalid organisation.')); + } + $organisation = $this->Organisations->get($id, [ + 'contain' => ['Alignments' => 'Individuals'] + ]); + if ($this->_isRest()) { + return $this->RestResponse->viewData($organisation, 'json'); + } else { + + } + $this->set('metaGroup', 'ContactDB'); + $this->set('organisation', $organisation); + } + + public function edit($id) + { + if (empty($id)) { + throw new NotFoundException(__('Invalid organisation.')); + } + $organisation = $this->Organisations->get($id); + if ($this->request->is(['post', 'put'])) { + $this->Organisations->patchEntity($organisation, $this->request->getData()); + if ($this->Organisations->save($organisation)) { + $message = __('Organisation updated.'); + if ($this->_isRest()) { + $organisation = $this->Organisations->get($id); + return $this->RestResponse->viewData($organisation, 'json'); + } else { + $this->Flash->success($message); + return $this->redirect(['action' => 'index']); + } + } else { + if ($this->_isRest()) { + + } + } + } + $this->set('metaGroup', 'ContactDB'); + $this->set('organisation', $organisation); + $this->render('add'); + } + + public function delete($id) + { + if (empty($id)) { + throw new NotFoundException(__('Invalid organisation.')); + } + $organisation = $this->Organisations->get($id); + if ($this->request->is('post') || $this->request->is('delete')) { + if ($this->Organisations->delete($organisation)) { + $message = __('Organisation deleted.'); + if ($this->_isRest()) { + $organisation = $this->Organisations->get($id); + return $this->RestResponse->saveSuccessResponse('Organisations', 'delete', $id, 'json', $message); + } else { + $this->Flash->success($message); + return $this->redirect($this->referer()); + } + } + } + $this->set('metaGroup', 'ContactDB'); + $this->set('scope', 'organisations'); + $this->set('id', $organisation['id']); + $this->set('organisation', $organisation); + $this->viewBuilder()->setLayout('ajax'); + $this->render('/genericTemplates/delete'); + } +} diff --git a/app/src/Controller/PagesController.php b/app/src/Controller/PagesController.php new file mode 100644 index 0000000..5ad4740 --- /dev/null +++ b/app/src/Controller/PagesController.php @@ -0,0 +1,75 @@ +redirect('/'); + } + if (in_array('..', $path, true) || in_array('.', $path, true)) { + throw new ForbiddenException(); + } + $page = $subpage = null; + + if (!empty($path[0])) { + $page = $path[0]; + } + if (!empty($path[1])) { + $subpage = $path[1]; + } + $this->set(compact('page', 'subpage')); + + try { + return $this->render(implode('/', $path)); + } catch (MissingTemplateException $exception) { + if (Configure::read('debug')) { + throw $exception; + } + throw new NotFoundException(); + } + + return $this->render(); + } +} diff --git a/app/src/Model/Behavior/.gitkeep b/app/src/Model/Behavior/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/Model/Entity/.gitkeep b/app/src/Model/Entity/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/Model/Entity/Alignment.php b/app/src/Model/Entity/Alignment.php new file mode 100644 index 0000000..a969770 --- /dev/null +++ b/app/src/Model/Entity/Alignment.php @@ -0,0 +1,11 @@ +belongsTo('Individuals'); + $this->belongsTo('Organisations'); + } + + public function validationDefault(Validator $validator): Validator + { + $validator + ->notEmptyString('individual_id') + ->notEmptyString('organisation_id') + ->requirePresence(['individual_id', 'organisation_id'], 'create'); + return $validator; + } +} diff --git a/app/src/Model/Table/AppTable.php b/app/src/Model/Table/AppTable.php new file mode 100644 index 0000000..09a5669 --- /dev/null +++ b/app/src/Model/Table/AppTable.php @@ -0,0 +1,13 @@ +belongsTo( + 'Individuals', + [ + 'foreignKey' => 'owner_id', + 'conditions' => ['owner_type' => 'individual'] + ] + ); + $this->belongsTo( + 'Organisations', + [ + 'foreignKey' => 'owner_id', + 'conditions' => ['owner_type' => 'organisation'] + ] + ); + } + + public function validationDefault(Validator $validator): Validator + { + $validator + ->notEmptyString('type') + ->notEmptyString('encryption_key') + ->notEmptyString('uuid') + ->notEmptyString('owner_id') + ->notEmptyString('owner_type') + ->requirePresence(['type', 'encryption_key', 'uuid', 'owner_id', 'owner_type'], 'create'); + return $validator; + } +} diff --git a/app/src/Model/Table/IndividualsTable.php b/app/src/Model/Table/IndividualsTable.php new file mode 100644 index 0000000..743909c --- /dev/null +++ b/app/src/Model/Table/IndividualsTable.php @@ -0,0 +1,32 @@ +hasMany('Alignments'); + $this->hasMany( + 'EncryptionKeys', + [ + 'foreignKey' => 'owner_id', + 'conditions' => ['owner_type' => 'individual'] + ] + ); + } + + public function validationDefault(Validator $validator): Validator + { + $validator + ->notEmptyString('email') + ->notEmptyString('uuid') + ->requirePresence(['email', 'uuid'], 'create'); + return $validator; + } +} diff --git a/app/src/Model/Table/OrganisationsTable.php b/app/src/Model/Table/OrganisationsTable.php new file mode 100644 index 0000000..a7c5439 --- /dev/null +++ b/app/src/Model/Table/OrganisationsTable.php @@ -0,0 +1,32 @@ +hasMany('Alignments'); + $this->hasMany( + 'EncryptionKeys', + [ + 'foreignKey' => 'owner_id', + 'conditions' => ['owner_type' => 'organisation'] + ] + ); + } + + public function validationDefault(Validator $validator): Validator + { + $validator + ->notEmptyString('name') + ->notEmptyString('uuid') + ->requirePresence(['name', 'uuid'], 'create'); + return $validator; + } +} diff --git a/app/src/Model/Validation/ValidationCollection.php b/app/src/Model/Validation/ValidationCollection.php new file mode 100644 index 0000000..6d8f84f --- /dev/null +++ b/app/src/Model/Validation/ValidationCollection.php @@ -0,0 +1,13 @@ +response = $this->response->withType('ajax'); + } +} diff --git a/app/src/View/AppView.php b/app/src/View/AppView.php new file mode 100644 index 0000000..6abc2b1 --- /dev/null +++ b/app/src/View/AppView.php @@ -0,0 +1,45 @@ +loadHelper('Html');` + * + * @return void + */ + public function initialize(): void + { + parent::initialize(); + $this->loadHelper('Hash'); + $this->loadHelper('Paginator', ['templates' => 'cerebrate-pagination-templates']); + } +} diff --git a/app/src/View/Cell/.gitkeep b/app/src/View/Cell/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/View/Helper/.gitkeep b/app/src/View/Helper/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/View/Helper/FontAwesomeHelper.php b/app/src/View/Helper/FontAwesomeHelper.php new file mode 100644 index 0000000..9b34bce --- /dev/null +++ b/app/src/View/Helper/FontAwesomeHelper.php @@ -0,0 +1,450 @@ +findNamespace($icon) . ' fa-' . $icon; + } + + public function findNamespace($icon) + { + $fab_icons = array( + '500px', + 'accessible-icon', + 'accusoft', + 'acquisitions-incorporated', + 'adn', + 'adobe', + 'adversal', + 'affiliatetheme', + 'airbnb', + 'algolia', + 'alipay', + 'amazon', + 'amazon-pay', + 'amilia', + 'android', + 'angellist', + 'angrycreative', + 'angular', + 'app-store', + 'app-store-ios', + 'apper', + 'apple', + 'apple-pay', + 'artstation', + 'asymmetrik', + 'atlassian', + 'audible', + 'autoprefixer', + 'avianex', + 'aviato', + 'aws', + 'bandcamp', + 'battle-net', + 'behance', + 'behance-square', + 'bimobject', + 'bitbucket', + 'bitcoin', + 'bity', + 'black-tie', + 'blackberry', + 'blogger', + 'blogger-b', + 'bluetooth', + 'bluetooth-b', + 'bootstrap', + 'btc', + 'buffer', + 'buromobelexperte', + 'canadian-maple-leaf', + 'cc-amazon-pay', + 'cc-amex', + 'cc-apple-pay', + 'cc-diners-club', + 'cc-discover', + 'cc-jcb', + 'cc-mastercard', + 'cc-paypal', + 'cc-stripe', + 'cc-visa', + 'centercode', + 'centos', + 'chrome', + 'chromecast', + 'cloudscale', + 'cloudsmith', + 'cloudversify', + 'codepen', + 'codiepie', + 'confluence', + 'connectdevelop', + 'contao', + 'cpanel', + 'creative-commons', + 'creative-commons-by', + 'creative-commons-nc', + 'creative-commons-nc-eu', + 'creative-commons-nc-jp', + 'creative-commons-nd', + 'creative-commons-pd', + 'creative-commons-pd-alt', + 'creative-commons-remix', + 'creative-commons-sa', + 'creative-commons-sampling', + 'creative-commons-sampling-plus', + 'creative-commons-share', + 'creative-commons-zero', + 'critical-role', + 'css3', + 'css3-alt', + 'cuttlefish', + 'd-and-d', + 'd-and-d-beyond', + 'dashcube', + 'delicious', + 'deploydog', + 'deskpro', + 'dev', + 'deviantart', + 'dhl', + 'diaspora', + 'digg', + 'digital-ocean', + 'discord', + 'discourse', + 'dochub', + 'docker', + 'draft2digital', + 'dribbble', + 'dribbble-square', + 'dropbox', + 'drupal', + 'dyalog', + 'earlybirds', + 'ebay', + 'edge', + 'elementor', + 'ello', + 'ember', + 'empire', + 'envira', + 'erlang', + 'ethereum', + 'etsy', + 'evernote', + 'expeditedssl', + 'facebook', + 'facebook-f', + 'facebook-messenger', + 'facebook-square', + 'fantasy-flight-games', + 'fedex', + 'fedora', + 'figma', + 'firefox', + 'first-order', + 'first-order-alt', + 'firstdraft', + 'flickr', + 'flipboard', + 'fly', + 'font-awesome', + 'font-awesome-alt', + 'font-awesome-flag', + 'fonticons', + 'fonticons-fi', + 'fort-awesome', + 'fort-awesome-alt', + 'forumbee', + 'foursquare', + 'free-code-camp', + 'freebsd', + 'fulcrum', + 'galactic-republic', + 'galactic-senate', + 'get-pocket', + 'gg', + 'gg-circle', + 'git', + 'git-square', + 'github', + 'github-alt', + 'github-square', + 'gitkraken', + 'gitlab', + 'gitter', + 'glide', + 'glide-g', + 'gofore', + 'goodreads', + 'goodreads-g', + 'google', + 'google-drive', + 'google-play', + 'google-plus', + 'google-plus-g', + 'google-plus-square', + 'google-wallet', + 'gratipay', + 'grav', + 'gripfire', + 'grunt', + 'gulp', + 'hacker-news', + 'hacker-news-square', + 'hackerrank', + 'hips', + 'hire-a-helper', + 'hooli', + 'hornbill', + 'hotjar', + 'houzz', + 'html5', + 'hubspot', + 'imdb', + 'instagram', + 'intercom', + 'internet-explorer', + 'invision', + 'ioxhost', + 'itch-io', + 'itunes', + 'itunes-note', + 'java', + 'jedi-order', + 'jenkins', + 'jira', + 'joget', + 'joomla', + 'js', + 'js-square', + 'jsfiddle', + 'kaggle', + 'keybase', + 'keycdn', + 'kickstarter', + 'kickstarter-k', + 'korvue', + 'laravel', + 'lastfm', + 'lastfm-square', + 'leanpub', + 'less', + 'line', + 'linkedin', + 'linkedin-in', + 'linode', + 'linux', + 'lyft', + 'magento', + 'mailchimp', + 'mandalorian', + 'markdown', + 'mastodon', + 'maxcdn', + 'medapps', + 'medium', + 'medium-m', + 'medrt', + 'meetup', + 'megaport', + 'mendeley', + 'microsoft', + 'mix', + 'mixcloud', + 'mizuni', + 'modx', + 'monero', + 'napster', + 'neos', + 'nimblr', + 'nintendo-switch', + 'node', + 'node-js', + 'npm', + 'ns8', + 'nutritionix', + 'odnoklassniki', + 'odnoklassniki-square', + 'old-republic', + 'opencart', + 'openid', + 'opera', + 'optin-monster', + 'osi', + 'page4', + 'pagelines', + 'palfed', + 'patreon', + 'paypal', + 'penny-arcade', + 'periscope', + 'phabricator', + 'phoenix-framework', + 'phoenix-squadron', + 'php', + 'pied-piper', + 'pied-piper-alt', + 'pied-piper-hat', + 'pied-piper-pp', + 'pinterest', + 'pinterest-p', + 'pinterest-square', + 'playstation', + 'product-hunt', + 'pushed', + 'python', + 'qq', + 'quinscape', + 'quora', + 'r-project', + 'raspberry-pi', + 'ravelry', + 'react', + 'reacteurope', + 'readme', + 'rebel', + 'red-river', + 'reddit', + 'reddit-alien', + 'reddit-square', + 'redhat', + 'renren', + 'replyd', + 'researchgate', + 'resolving', + 'rev', + 'rocketchat', + 'rockrms', + 'safari', + 'salesforce', + 'sass', + 'schlix', + 'scribd', + 'searchengin', + 'sellcast', + 'sellsy', + 'servicestack', + 'shirtsinbulk', + 'shopware', + 'simplybuilt', + 'sistrix', + 'sith', + 'sketch', + 'skyatlas', + 'skype', + 'slack', + 'slack-hash', + 'slideshare', + 'snapchat', + 'snapchat-ghost', + 'snapchat-square', + 'soundcloud', + 'sourcetree', + 'speakap', + 'speaker-deck', + 'spotify', + 'squarespace', + 'stack-exchange', + 'stack-overflow', + 'staylinked', + 'steam', + 'steam-square', + 'steam-symbol', + 'sticker-mule', + 'strava', + 'stripe', + 'stripe-s', + 'studiovinari', + 'stumbleupon', + 'stumbleupon-circle', + 'superpowers', + 'supple', + 'suse', + 'symfony', + 'teamspeak', + 'telegram', + 'telegram-plane', + 'tencent-weibo', + 'the-red-yeti', + 'themeco', + 'themeisle', + 'think-peaks', + 'trade-federation', + 'trello', + 'tripadvisor', + 'tumblr', + 'tumblr-square', + 'twitch', + 'twitter', + 'twitter-square', + 'typo3', + 'uber', + 'ubuntu', + 'uikit', + 'uniregistry', + 'untappd', + 'ups', + 'usb', + 'usps', + 'ussunnah', + 'vaadin', + 'viacoin', + 'viadeo', + 'viadeo-square', + 'viber', + 'vimeo', + 'vimeo-square', + 'vimeo-v', + 'vine', + 'vk', + 'vnv', + 'vuejs', + 'waze', + 'weebly', + 'weibo', + 'weixin', + 'whatsapp', + 'whatsapp-square', + 'whmcs', + 'wikipedia-w', + 'windows', + 'wix', + 'wizards-of-the-coast', + 'wolf-pack-battalion', + 'wordpress', + 'wordpress-simple', + 'wpbeginner', + 'wpexplorer', + 'wpforms', + 'wpressr', + 'xbox', + 'xing', + 'xing-square', + 'y-combinator', + 'yahoo', + 'yammer', + 'yandex', + 'yandex-international', + 'yarn', + 'yelp', + 'yoast', + 'youtube', + 'youtube-square', + 'zhihu' + ); + if (in_array($icon, $fab_icons)) { + return 'fab'; + } else { + return 'fas'; + } + } + } diff --git a/app/src/View/Helper/HashHelper.php b/app/src/View/Helper/HashHelper.php new file mode 100644 index 0000000..5a2cbef --- /dev/null +++ b/app/src/View/Helper/HashHelper.php @@ -0,0 +1,14 @@ +element('genericElements/Form/genericForm', array( + 'form' => $this->Form, + 'data' => array( + 'entity' => $alignment, + 'title' => __('Add new alignment for {0} #{1}', \Cake\Utility\Inflector::singularize(h($scope)), h($source_id)), + 'description' => __('Alignments indicate that an individual belongs to an organisation in one way or another. The type of relationship is defined by the type field.'), + 'model' => 'Organisations', + 'fields' => array( + array( + 'field' => ($scope === 'individuals' ? 'organisation_id' : 'individual_id'), + 'options' => ($scope === 'individuals' ? $organisations : $individuals), + 'type' => 'select' + ), + array( + 'field' => 'type' + ) + ), + 'submit' => array( + 'action' => $this->request->getParam('action') + ) + ) +)); diff --git a/app/templates/EncryptionKeys/add.php b/app/templates/EncryptionKeys/add.php new file mode 100644 index 0000000..0a7afb1 --- /dev/null +++ b/app/templates/EncryptionKeys/add.php @@ -0,0 +1,30 @@ + 'email', 'organisation' => 'name']; +echo $this->element('genericElements/Form/genericForm', array( + 'form' => $this->Form, + 'data' => array( + 'entity' => $encryptionKey, + 'title' => __('Add new encryption key for {0} #{1} ({2})', h($owner_type), h($owner_id), h($owner[$primaryIdentifiers[$owner_type]])), + 'description' => __('Alignments indicate that an individual belongs to an organisation in one way or another. The type of relationship is defined by the type field.'), + 'model' => 'Organisations', + 'fields' => array( + array( + 'field' => 'uuid', + 'type' => 'uuid' + ), + array( + 'field' => 'type', + 'options' => array('pgp' => 'PGP', 'smime' => 'S/MIME') + ), + array( + 'field' => 'encryption_key', + 'label' => __('Public key'), + 'type' => 'textarea', + 'rows' => 8 + ) + ), + 'submit' => array( + 'action' => $this->request->getParam('action') + ) + ) +)); diff --git a/app/templates/Error/error400.php b/app/templates/Error/error400.php new file mode 100644 index 0000000..8096901 --- /dev/null +++ b/app/templates/Error/error400.php @@ -0,0 +1,38 @@ +layout = 'error'; + +if (Configure::read('debug')) : + $this->layout = 'dev_error'; + + $this->assign('title', $message); + $this->assign('templateName', 'error400.php'); + + $this->start('file'); +?> +queryString)) : ?> +

    + SQL Query: + queryString) ?> +

    + +params)) : ?> + SQL Query Params: + params) ?> + +element('auto_table_warning') ?> +end(); +endif; +?> +

    +

    + : + '{$url}'") ?> +

    diff --git a/app/templates/Error/error500.php b/app/templates/Error/error500.php new file mode 100644 index 0000000..4ade4dd --- /dev/null +++ b/app/templates/Error/error500.php @@ -0,0 +1,42 @@ +layout = 'error'; + +if (Configure::read('debug')) : + $this->layout = 'dev_error'; + + $this->assign('title', $message); + $this->assign('templateName', 'error500.php'); + + $this->start('file'); +?> +queryString)) : ?> +

    + SQL Query: + queryString) ?> +

    + +params)) : ?> + SQL Query Params: + params) ?> + + + Error in: + getFile()), $error->getLine()) ?> + +element('auto_table_warning'); + + $this->end(); +endif; +?> +

    +

    + : + +

    diff --git a/app/templates/Individuals/add.php b/app/templates/Individuals/add.php new file mode 100644 index 0000000..dbb2f17 --- /dev/null +++ b/app/templates/Individuals/add.php @@ -0,0 +1,35 @@ +element('genericElements/Form/genericForm', array( + 'form' => $this->Form, + 'data' => array( + 'entity' => $individual, + 'title' => __('Add new individual'), + 'description' => __('Individuals are natural persons. They are meant to describe the basic information about an individual that may or may not be a user of this community. Users in genral require an individual object to identify the person behind them - however, no user account is required to store information about an individual. Individuals can have affiliations to organisations and broods as well as cryptographic keys, using which their messages can be verified and which can be used to securely contact them.'), + 'model' => 'Organisations', + 'fields' => array( + array( + 'field' => 'email' + ), + array( + 'field' => 'first_name' + ), + array( + 'field' => 'last_name' + ), + array( + 'field' => 'position' + ), + array( + 'field' => 'uuid', + 'label' => 'UUID', + 'type' => 'uuid' + ) + ), + 'submit' => array( + 'action' => $this->request->getParam('action') + ) + ) + )); +?> + diff --git a/app/templates/Individuals/index.php b/app/templates/Individuals/index.php new file mode 100644 index 0000000..491a9fb --- /dev/null +++ b/app/templates/Individuals/index.php @@ -0,0 +1,74 @@ +element('genericElements/IndexTable/index_table', [ + 'data' => [ + 'data' => $data, + 'top_bar' => [ + 'pull' => 'right', + 'children' => [ + [ + 'type' => 'search', + 'button' => __('Filter'), + 'placeholder' => __('Enter value to search'), + 'data' => '', + 'searchKey' => 'value' + ] + ] + ], + 'fields' => [ + [ + 'name' => '#', + 'sort' => 'id', + 'data_path' => 'id', + ], + [ + 'name' => __('Email'), + 'sort' => 'email', + 'data_path' => 'email', + ], + [ + 'name' => __('First Name'), + 'sort' => 'first_name', + 'data_path' => 'first_name', + ], + [ + 'name' => __('Last Name'), + 'sort' => 'last_name', + 'data_path' => 'last_name', + ], + [ + 'name' => __('Alignments'), + 'data_path' => 'alignments', + 'element' => 'alignments', + 'scope' => $alignmentScope + ], + [ + 'name' => __('UUID'), + 'sort' => 'uuid', + 'data_path' => 'uuid', + 'placeholder' => __('Leave empty to auto generate') + ], + ], + 'title' => __('ContactDB Individuals Index'), + 'description' => __('A list of individuals known by your Cerebrate instance. This list can get populated either directly, by adding new individuals or by fetching them from trusted remote sources. Additionally, users created for the platform will always have an individual identity.'), + 'pull' => 'right', + 'actions' => [ + [ + 'url' => '/individuals/view', + 'url_params_data_paths' => ['id'], + 'icon' => 'eye' + ], + [ + 'url' => '/individuals/edit', + 'url_params_data_paths' => ['id'], + 'icon' => 'edit' + ], + [ + 'onclick' => 'populateAndLoadModal(\'/individuals/delete/[onclick_params_data_path]\');', + 'onclick_params_data_path' => 'id', + 'icon' => 'trash' + ] + ] + ] +]); +echo ''; +?> diff --git a/app/templates/Individuals/view.php b/app/templates/Individuals/view.php new file mode 100644 index 0000000..510c142 --- /dev/null +++ b/app/templates/Individuals/view.php @@ -0,0 +1,41 @@ +element( + '/genericElements/SingleViews/single_view', + [ + 'title' => __('Individual View'), + 'data' => $individual, + 'fields' => [ + [ + 'key' => __('ID'), + 'path' => 'id' + ], + [ + 'key' => __('Email'), + 'path' => 'email' + ], + [ + 'key' => __('UUID'), + 'path' => 'uuid' + ], + [ + 'key' => __('First Name'), + 'path' => 'first_name' + ], + [ + 'key' => __('Last Name'), + 'path' => 'last_name' + ], + [ + 'key' => __('Position'), + 'path' => 'position' + ], + [ + 'key' => __('Alignments'), + 'type' => 'alignment', + 'path' => 'alignments', + 'scope' => 'individuals' + ] + ], + 'children' => [] + ] +); diff --git a/app/templates/Organisations/add.php b/app/templates/Organisations/add.php new file mode 100644 index 0000000..203c9ce --- /dev/null +++ b/app/templates/Organisations/add.php @@ -0,0 +1,42 @@ +element('genericElements/Form/genericForm', array( + 'form' => $this->Form, + 'data' => array( + 'entity' => $organisation, + 'title' => __('Add new organisation'), + 'description' => __('Organisations can be equivalent to legal entities or specific individual teams within such entities. Their purpose is to relate individuals to their affiliations and for release control of information using the Trust Circles.'), + 'model' => 'Organisations', + 'fields' => array( + array( + 'field' => 'name' + ), + array( + 'field' => 'description', + 'type' => 'textarea' + ), + array( + 'field' => 'uuid', + 'label' => 'UUID', + 'type' => 'uuid' + ), + array( + 'field' => 'URL' + ), + array( + 'field' => 'nationality' + ), + array( + 'field' => 'sector' + ), + array( + 'field' => 'type' + ) + ), + 'submit' => array( + 'action' => $this->request->getParam('action') + ) + ) + )); +?> + diff --git a/app/templates/Organisations/index.php b/app/templates/Organisations/index.php new file mode 100644 index 0000000..2644953 --- /dev/null +++ b/app/templates/Organisations/index.php @@ -0,0 +1,84 @@ +element('genericElements/IndexTable/index_table', [ + 'data' => [ + 'data' => $data, + 'top_bar' => [ + 'pull' => 'right', + 'children' => [ + [ + 'type' => 'search', + 'button' => __('Filter'), + 'placeholder' => __('Enter value to search'), + 'data' => '', + 'searchKey' => 'value' + ] + ] + ], + 'fields' => [ + [ + 'name' => '#', + 'sort' => 'id', + 'class' => 'short', + 'data_path' => 'id', + ], + [ + 'name' => __('Name'), + 'class' => 'short', + 'data_path' => 'name', + ], + [ + 'name' => __('UUID'), + 'sort' => 'uuid', + 'class' => 'short', + 'data_path' => 'uuid', + ], + [ + 'name' => __('Members'), + 'data_path' => 'alignments', + 'element' => 'count_summary', + 'url' => '/individuals/index/?organisation_id={{url_data}}', + 'url_data_path' => 'id' + ], + [ + 'name' => __('URL'), + 'sort' => 'url', + 'class' => 'short', + 'data_path' => 'url', + ], + [ + 'name' => __('Nationality'), + 'data_path' => 'nationality', + ], + [ + 'name' => __('Sector'), + 'data_path' => 'sector', + ], + [ + 'name' => __('Type'), + 'data_path' => 'type', + ] + ], + 'title' => __('ContactDB Organisation Index'), + 'description' => __('A list of organisations known by your Cerebrate instance. This list can get populated either directly, by adding new organisations or by fetching them from trusted remote sources.'), + 'pull' => 'right', + 'actions' => [ + [ + 'url' => '/organisations/view', + 'url_params_data_paths' => ['id'], + 'icon' => 'eye' + ], + [ + 'url' => '/organisations/edit', + 'url_params_data_paths' => ['id'], + 'icon' => 'edit' + ], + [ + 'onclick' => 'populateAndLoadModal(\'/organisations/delete/[onclick_params_data_path]\');', + 'onclick_params_data_path' => 'id', + 'icon' => 'trash' + ] + ] + ] +]); +echo ''; +?> diff --git a/app/templates/Organisations/view.php b/app/templates/Organisations/view.php new file mode 100644 index 0000000..d63655b --- /dev/null +++ b/app/templates/Organisations/view.php @@ -0,0 +1,49 @@ +element( + '/genericElements/SingleViews/single_view', + array( + 'title' => __('Organisation View'), + 'data' => $organisation, + 'fields' => array( + [ + 'key' => __('ID'), + 'path' => 'id' + ], + [ + 'key' => __('Name'), + 'path' => 'name' + ], + [ + 'key' => __('UUID'), + 'path' => 'uuid' + ], + [ + 'key' => __('URL'), + 'path' => 'url' + ], + [ + 'key' => __('Nationality'), + 'path' => 'nationality' + ], + [ + 'key' => __('Sector'), + 'path' => 'sector' + ], + [ + 'key' => __('Type'), + 'path' => 'type' + ], + [ + 'key' => __('Contacts'), + 'path' => 'contacts' + ], + [ + 'key' => __('Alignments'), + 'type' => 'alignment', + 'path' => 'alignments', + 'scope' => 'organisations' + ] + ), + 'children' => [] + ) +); diff --git a/app/templates/Pages/home.php b/app/templates/Pages/home.php new file mode 100644 index 0000000..0b50457 --- /dev/null +++ b/app/templates/Pages/home.php @@ -0,0 +1,222 @@ +disableAutoLayout(); + +if (!Configure::read('debug')) : + throw new NotFoundException( + 'Please replace templates/Pages/home.php with your own version or re-enable debug mode.' + ); +endif; + +$cakeDescription = 'CakePHP: the rapid development PHP framework'; +?> + + + + Html->charset() ?> + + + <?= $cakeDescription ?>: + <?= $this->fetch('title') ?> + + Html->meta('icon') ?> + + + + + Html->css('milligram.min.css') ?> + Html->css('cake.css') ?> + Html->css('home.css') ?> + + fetch('meta') ?> + fetch('css') ?> + fetch('script') ?> + + +
    +
    + + CakePHP + +

    + Welcome to CakePHP Strawberry +

    +
    +
    +
    +
    +
    +
    +
    +
    + Please be aware that this page will not be shown if you turn off debug mode unless you replace templates/Pages/home.php with your own version. +
    + + +
    +
    +
    +
    +

    Environment

    +
      + =')) : ?> +
    • Your version of PHP is 7.2.0 or higher (detected ).
    • + +
    • Your version of PHP is too low. You need PHP 7.2.0 or higher to use CakePHP (detected ).
    • + + + +
    • Your version of PHP has the mbstring extension loaded.
    • + +
    • Your version of PHP does NOT have the mbstring extension loaded.
    • + + + +
    • Your version of PHP has the openssl extension loaded.
    • + +
    • Your version of PHP has the mcrypt extension loaded.
    • + +
    • Your version of PHP does NOT have the openssl or mcrypt extension loaded.
    • + + + +
    • Your version of PHP has the intl extension loaded.
    • + +
    • Your version of PHP does NOT have the intl extension loaded.
    • + +
    +
    +
    +

    Filesystem

    +
      + +
    • Your tmp directory is writable.
    • + +
    • Your tmp directory is NOT writable.
    • + + + +
    • Your logs directory is writable.
    • + +
    • Your logs directory is NOT writable.
    • + + + + +
    • The Engine is being used for core caching. To change the config edit config/app.php
    • + +
    • Your cache is NOT working. Please check the settings in config/app.php
    • + +
    +
    +
    +
    +
    +
    +

    Database

    + connect(); + } catch (Exception $connectionError) { + $connected = false; + $errorMsg = $connectionError->getMessage(); + if (method_exists($connectionError, 'getAttributes')) : + $attributes = $connectionError->getAttributes(); + if (isset($errorMsg['message'])) : + $errorMsg .= '
    ' . $attributes['message']; + endif; + endif; + } + ?> +
      + +
    • CakePHP is able to connect to the database.
    • + +
    • CakePHP is NOT able to connect to the database.
    • + +
    +
    +
    +

    DebugKit

    +
      + +
    • DebugKit is loaded.
    • + +
    • DebugKit is NOT loaded. You need to either install pdo_sqlite, or define the "debug_kit" connection name.
    • + +
    +
    +
    +
    +
    + +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + + diff --git a/app/templates/cell/.gitkeep b/app/templates/cell/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/app/templates/cell/.gitkeep @@ -0,0 +1 @@ + diff --git a/app/templates/element/flash/default.php b/app/templates/element/flash/default.php new file mode 100644 index 0000000..f86e90f --- /dev/null +++ b/app/templates/element/flash/default.php @@ -0,0 +1,20 @@ + + diff --git a/app/templates/element/flash/error.php b/app/templates/element/flash/error.php new file mode 100644 index 0000000..09d03ec --- /dev/null +++ b/app/templates/element/flash/error.php @@ -0,0 +1,16 @@ + + diff --git a/app/templates/element/flash/success.php b/app/templates/element/flash/success.php new file mode 100644 index 0000000..edf11ca --- /dev/null +++ b/app/templates/element/flash/success.php @@ -0,0 +1,16 @@ + + diff --git a/app/templates/element/genericElements/Form/Fields/checkboxField.php b/app/templates/element/genericElements/Form/Fields/checkboxField.php new file mode 100644 index 0000000..9354f0f --- /dev/null +++ b/app/templates/element/genericElements/Form/Fields/checkboxField.php @@ -0,0 +1,8 @@ +control($fieldData['field'], $params); + if (!empty($fieldData['hidden'])) { + $temp = ''; + } + echo $temp; +?> diff --git a/app/templates/element/genericElements/Form/Fields/genericField.php b/app/templates/element/genericElements/Form/Fields/genericField.php new file mode 100644 index 0000000..ccee3e2 --- /dev/null +++ b/app/templates/element/genericElements/Form/Fields/genericField.php @@ -0,0 +1,9 @@ +control($fieldData['field'], $params); + if (!empty($fieldData['hidden'])) { + $temp = ''; + } + echo $temp; +?> diff --git a/app/templates/element/genericElements/Form/Fields/uuidField.php b/app/templates/element/genericElements/Form/Fields/uuidField.php new file mode 100644 index 0000000..6600bd3 --- /dev/null +++ b/app/templates/element/genericElements/Form/Fields/uuidField.php @@ -0,0 +1,42 @@ +Form->setTemplates([ + 'inputContainer' => '{{content}}', + 'inputContainerError' => '{{content}}', + 'formGroup' => '{{input}}', + ]); + $label = $fieldData['label']; + $temp = sprintf( + '
    +
    %s
    +
    +
    + %s%s +
    +
    +
    ', + h($label), + $form->control($fieldData['field'], $params), + sprintf( + '%s', + $random, + __('Generate') + ) + ); + echo $temp; +?> + diff --git a/app/templates/element/genericElements/Form/formInfo.php b/app/templates/element/genericElements/Form/formInfo.php new file mode 100644 index 0000000..419bdec --- /dev/null +++ b/app/templates/element/genericElements/Form/formInfo.php @@ -0,0 +1,47 @@ + $fieldDesc); + $default = 'info'; + } else { + if (!empty($field['options'])) { + if (isset($this->request->data[$modelForForm][$field['field']])) { + $default = $this->request->data[$modelForForm][$field['field']]; + } else { + reset($field['options']); + $default = key($field['options']); + } + } else { + reset($fieldDesc); + $fieldDesc = array('info' => key($fieldDesc)); + $default = 'info'; + } + } + echo sprintf( + '', + h($field['field']) + ); +?> + diff --git a/app/templates/element/genericElements/Form/genericForm.php b/app/templates/element/genericElements/Form/genericForm.php new file mode 100644 index 0000000..47b8b19 --- /dev/null +++ b/app/templates/element/genericElements/Form/genericForm.php @@ -0,0 +1,160 @@ +Form->input(), + * - requirements: boolean, if false is passed the field is skipped + * - metafields: fields that are outside of the scope of the form itself + - use these to define dynamic form fields, or anything that will feed into the regular fields via JS population + * - submit: The submit button itself. By default it will simply submit to the form as defined via the 'model' field + */ + $modelForForm = empty($data['model']) ? + h(\Cake\Utility\Inflector::singularize(\Cake\Utility\Inflector::classify($this->request->getParam('controller')))) : + h($data['model']); + $fieldsString = ''; + $simpleFieldWhitelist = array( + 'default', 'type', 'options', 'placeholder', 'label', 'empty', 'rows', 'div', 'required' + ); + $fieldsArrayForPersistence = array(); + if (empty($data['url'])) { + $data['url'] = ["controller" => $this->request->getParam('controller'), "action" => $this->request->getParam('url')]; + } + $formRandomValue = Cake\Utility\Security::randomString(8); + $formCreate = $this->Form->create($data['entity'], ['id' => 'form-' . $formRandomValue]); + $default_template = [ + 'inputContainer' => '
    {{content}}
    ', + 'inputContainerError' => '
    {{content}}
    ', + 'label' => '{{text}}', + 'input' => '', + 'textarea' => '', + 'select' => '', + 'checkbox' => '', + 'checkboxFormGroup' => '{{label}}', + 'checkboxWrapper' => '
    {{label}}
    ', + 'formGroup' => '
    {{label}}
    {{input}}
    ', + 'nestingLabel' => '{{hidden}}
    {{text}}
    {{input}}
    ', + ]; + if (!empty($data['fields'])) { + foreach ($data['fields'] as $fieldData) { + // we reset the template each iteration as individual fields might override the defaults. + $this->Form->setTemplates($default_template); + if (isset($fieldData['requirements']) && !$fieldData['requirements']) { + continue; + } + if (is_array($fieldData)) { + if (empty($fieldData['type'])) { + $fieldData['type'] = 'text'; + } + $fieldTemplate = 'genericField'; + if (file_exists(ROOT . '/templates/element/genericElements/Form/Fields/' . $fieldData['type'] . 'Field.php')) { + $fieldTemplate = $fieldData['type'] . 'Field'; + } + if (empty($fieldData['label'])) { + $fieldData['label'] = \Cake\Utility\Inflector::humanize($fieldData['field']); + } + if (!empty($fieldDesc[$fieldData['field']])) { + $fieldData['label'] .= $this->element( + 'genericElements/Form/formInfo', array( + 'field' => $fieldData, + 'fieldDesc' => $fieldDesc[$fieldData['field']], + 'modelForForm' => $modelForForm + ) + ); + } + $params = array(); + if (!empty($fieldData['class'])) { + if (is_array($fieldData['class'])) { + $class = implode(' ', $fieldData['class']); + } else { + $class = $fieldData['class']; + } + $params['class'] = $class; + } else { + $params['class'] = ''; + } + if (empty($fieldData['type']) || $fieldData['type'] !== 'checkbox' ) { + $params['class'] .= ' form-control'; + } + //$params['class'] = sprintf('form-control %s', $params['class']); + foreach ($simpleFieldWhitelist as $f) { + if (!empty($fieldData[$f])) { + $params[$f] = $fieldData[$f]; + } + } + $temp = $this->element('genericElements/Form/Fields/' . $fieldTemplate, array( + 'fieldData' => $fieldData, + 'params' => $params, + 'form' => $this->Form + )); + if (!empty($fieldData['hidden'])) { + $temp = ''; + } + $fieldsString .= $temp; + $fieldsArrayForPersistence []= $modelForForm . \Cake\Utility\Inflector::camelize($fieldData['field']); + } else { + $fieldsString .= $fieldData; + } + } + } + $metaFieldString = ''; + if (!empty($data['metaFields'])) { + foreach ($data['metaFields'] as $metaField) { + $metaFieldString .= $metaField; + } + } + $submitButtonData = array('model' => $modelForForm, 'formRandomValue' => $formRandomValue); + if (!empty($data['submit'])) { + $submitButtonData = array_merge($submitButtonData, $data['submit']); + } + if (!empty($data['ajaxSubmit'])) { + $submitButtonData['ajaxSubmit'] = $ajaxSubmit; + } + $ajaxFlashMessage = ''; + if ($ajax) { + $ajaxFlashMessage = sprintf( + '
    %s
    ', + $this->Flash->render() + ); + } + $formEnd = $this->Form->end(); + if (!empty($ajax)) { + echo $this->element('genericElements/genericModal', array( + 'title' => empty($data['title']) ? h(\Cake\Utility\Inflector::humanize($this->request->params['action'])) . ' ' . $modelForForm : h($data['title']), + 'body' => sprintf( + '%s%s%s%s%s%s', + empty($data['description']) ? '' : sprintf( + '
    %s
    ', + $data['description'] + ), + $ajaxFlashMessage, + $formCreate, + $fieldsString, + $formEnd, + $metaFieldString + ), + 'actionButton' => $this->element('genericElements/Form/submitButton', $submitButtonData), + 'class' => 'modal-lg' + )); + } else { + echo sprintf( + '%s

    %s

    %s%s%s%s%s%s%s%s', + empty($ajax) ? '
    ' : '', + empty($data['title']) ? h(\Cake\Utility\Inflector::humanize($this->request->params['action'])) . ' ' . $modelForForm : h($data['title']), + $formCreate, + $ajaxFlashMessage, + empty($data['description']) ? '' : sprintf( + '
    %s
    ', + $data['description'] + ), + $fieldsString, + $this->element('genericElements/Form/submitButton', $submitButtonData), + $formEnd, + $metaFieldString, + empty($ajax) ? '
    ' : '' + ); + } +?> diff --git a/app/templates/element/genericElements/Form/submitButton.php b/app/templates/element/genericElements/Form/submitButton.php new file mode 100644 index 0000000..e09fd13 --- /dev/null +++ b/app/templates/element/genericElements/Form/submitButton.php @@ -0,0 +1,17 @@ +%s', + "$('#form-" . h($formRandomValue) . "').submit()", + __('Submit') + ) + ); + } else { + echo $this->Form->button(empty($text) ? __('Submit') : h($text), [ + 'class' => 'btn btn-' . (empty($type) ? 'primary' : h($type)), + 'type' => 'submit' + ]); + } +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/actions.php b/app/templates/element/genericElements/IndexTable/Fields/actions.php new file mode 100644 index 0000000..3122f78 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/actions.php @@ -0,0 +1,96 @@ +'; + foreach ($actions as $action) { + if (isset($action['requirement']) && !$action['requirement']) { + continue; + } + if (isset($action['complex_requirement'])) { + if (isset($action['complex_requirement']['options']['datapath'])) { + foreach ($action['complex_requirement']['options']['datapath'] as $name => $path) { + $action['complex_requirement']['options']['datapath'][$name] = empty($this->Hash->extract($row, $path)[0]) ? null : $this->Hash->extract($row, $path)[0]; + } + } + $options = isset($action['complex_requirement']['options']) ? $action['complex_requirement']['options'] : array(); + $requirementMet = $action['complex_requirement']['function']($row, $options); + if (!$requirementMet) { + continue; + } + } + $url_param_data_paths = ''; + $url = empty($action['url']) ? '#' : h($action['url']); + if (!empty($action['url_params_data_paths'])) { + if (is_array($action['url_params_data_paths'])) { + $temp = array(); + foreach ($action['url_params_data_paths'] as $path) { + $temp[] = h(Cake\Utility\Hash::extract($row, $path)[0]); + } + $url_param_data_paths = implode('/', $temp); + } else { + $url_param_data_paths = h(Cake\Utility\Hash::extract($row, $action['url_params_data_paths'])[0]); + } + $url .= '/' . $url_param_data_paths; + } + if (!empty($action['url_named_params_data_paths'])) { + if (is_array($action['url_named_params_data_paths'])) { + $temp = array(); + foreach ($action['url_named_params_data_paths'] as $namedParam => $path) { + $temp[] = sprintf('%s:%s', h($namedParam), h($this->Hash->extract($row, $path)[0])); + } + $url_param_data_paths = implode('/', $temp); + } + $url .= '/' . $url_param_data_paths; + } + if (!empty($action['url_extension'])) { + $url .= '.' . $action['url_extension']; + } + if (isset($action['postLink'])) { + echo $this->Form->postLink( + '', + $url, + array( + 'class' => $this->FontAwesome->getClass($action['icon']) . ' black ' . (empty($action['class']) ? '' : h($action['class'])), + 'title' => empty($action['title']) ? '' : h($action['title']), + 'aria-label' => empty($action['aria-label']) ? '' : h($action['aria-label']), + ), + empty($action['postLinkConfirm'])? '' : $action['postLinkConfirm'] + ); + } else { + if (!empty($action['onclick']) && !empty($action['onclick_params_data_path'])) { + $action['onclick'] = str_replace( + '[onclick_params_data_path]', + h(Cake\Utility\Hash::extract($row, $action['onclick_params_data_path'])[0]), + $action['onclick'] + ); + + } + echo sprintf( + ' ', + $url, + empty($action['title']) ? '' : h($action['title']), + empty($action['title']) ? '' : h($action['title']), + empty($action['dbclickAction']) ? '' : 'class="dblclickActionElement"', + empty($action['onclick']) ? '' : sprintf('onClick="%s"', $action['onclick']), + $this->FontAwesome->getClass($action['icon']) + ); + } + } + echo ''; +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/alignments.php b/app/templates/element/genericElements/IndexTable/Fields/alignments.php new file mode 100644 index 0000000..aabc106 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/alignments.php @@ -0,0 +1,43 @@ +Hash->extract($row, $field['data_path']); +$alignments = ''; +if ($field['scope'] === 'individuals') { + foreach ($raw_alignments as $alignment) { + $alignments .= sprintf( + '
    %s @ %s
    ', + h($alignment['type']), + sprintf( + '%s', + h($alignment['organisation']['id']), + h($alignment['organisation']['name']) + ), + sprintf( + "populateAndLoadModal(%s);", + sprintf( + "'/alignments/delete/%s'", + $alignment['id'] + ) + ) + ); + } +} else if ($field['scope'] === 'organisations') { + foreach ($raw_alignments as $alignment) { + $alignments .= sprintf( + '
    [%s] %s
    ', + h($alignment['type']), + sprintf( + '%s', + h($alignment['individual']['id']), + h($alignment['individual']['email']) + ), + sprintf( + "populateAndLoadModal(%s);", + sprintf( + "'/alignments/delete/%s'", + $alignment['id'] + ) + ) + ); + } +} +echo $alignments; diff --git a/app/templates/element/genericElements/IndexTable/Fields/array_lookup_field.php b/app/templates/element/genericElements/IndexTable/Fields/array_lookup_field.php new file mode 100644 index 0000000..9f929f2 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/array_lookup_field.php @@ -0,0 +1,4 @@ +Hash->extract($row, $field['data_path'])[0]]); +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/boolean.php b/app/templates/element/genericElements/IndexTable/Fields/boolean.php new file mode 100644 index 0000000..b017046 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/boolean.php @@ -0,0 +1,57 @@ + array( + 'colour' => 'green', + 'text' => 'allowed' + ), + 'NOT' => array( + 'colour' => 'red', + 'text' => 'blocked' + ) + ); + if ( + !empty($this->Hash->extract($row, $field['data_path'])[0]) && + !empty($field['rule_path'][0]) && + !empty($this->Hash->extract($row, $field['rule_path'])[0]) + ) { + $rules = $this->Hash->extract($row, $field['rule_path'])[0]; + $rules = json_decode($rules, true); + foreach ($rules as $rule => $rule_data) { + if (is_array($rule_data)) { + foreach ($rule_data as $boolean => $values) { + if (!empty($values)) { + if (is_array($values)) { + $values = implode(', ', $values); + } + $rules_raw[] = sprintf( + '%s %s: %s', + h(\Cake\Utility\Inflector::humanize($rule)), + $typeOptions[$boolean]['text'], + $typeOptions[$boolean]['colour'], + h($values) + ); + } + } + } else if (!empty($rule_data)){ + $rules_raw[] = sprintf( + '%s: %s', + h(\Cake\Utility\Inflector::humanize($rule)), + h($rule_data) + ); + } + } + $rules_raw = implode('
    ', $rules_raw); + } + echo sprintf( + '%s', + (!empty($this->Hash->extract($row, $field['data_path'])[0])) ? 'check' : 'times', + empty($rules_raw) ? '' : + sprintf( + ' (%s)', + __('Filter rules'), + $rules_raw, + __('Rules') + ) + ); +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/caching.php b/app/templates/element/genericElements/IndexTable/Fields/caching.php new file mode 100644 index 0000000..3f6dca4 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/caching.php @@ -0,0 +1,32 @@ +Hash->extract($row, $field['data_path'])[0]; + $enabled = isset($field['enabled_path']) ? $this->Hash->extract($row, $field['enabled_path'])[0] : true; + if (!empty($timestamp)): + $units = array('m', 'h', 'd'); + $intervals = array(60, 60, 24); + $unit = 's'; + $last = time() - $timestamp; + foreach ($units as $k => $v) { + if ($last > $intervals[$k]) { + $unit = $v; + $last = floor($last / $intervals[$k]); + } else { + break; + } + } + $ageString = __('Age: ') . $last . $unit; + else: + $ageString = __('Not cached'); + endif; + echo sprintf( + '%s%s', + empty($timestamp) ? 'red bold' : '', + h($ageString), + (!$enabled || !$isSiteAdmin) ? '' : sprintf( + ' ', + $baseurl . '/feeds/cacheFeeds/' . h($primary), + __('Cache feed'), + __('Cache feed') + ) + ); +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/correlations.php b/app/templates/element/genericElements/IndexTable/Fields/correlations.php new file mode 100644 index 0000000..b5cc013 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/correlations.php @@ -0,0 +1,20 @@ +Hash->extract($row, $field['data_path']); + $scope_to_url = array( + 'event' => $baseurl . '/events/view' + ); + $correlations_html = array(); + foreach ($correlations as $id => $name) { + $correlations_html[] = sprintf( + '%s', + sprintf( + '%s/%s', + $scope_to_url[empty($scope) ? 'event' : $scope], + h($id) + ), + h($name), + h($id) + ); + } + echo implode(' ', $correlations_html); +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/count_summary.php b/app/templates/element/genericElements/IndexTable/Fields/count_summary.php new file mode 100644 index 0000000..69162cd --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/count_summary.php @@ -0,0 +1,25 @@ + __('Members'), +'data_path' => 'alignments', +'element' => 'count_summary', +'url' => '/individuals/index/?organisation_id={{url_data}}', +'url_data_path' => 'id' +*/ + $data = $this->Hash->extract($row, $field['data_path']); + if (!empty($field['url_data_path'])) { + $url_data_path = $this->Hash->extract($row, $field['url_data_path'])[0]; + } + if (!empty($field['url']) && count($data) > 0) { + if (!empty($url_data_path)) { + $field['url'] = str_replace('{{url_data}}', $url_data_path, $field['url']); + } + echo sprintf( + '%s', + h($field['url']), + count($data) + ); + } else { + echo count($data); + } +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/datetime.php b/app/templates/element/genericElements/IndexTable/Fields/datetime.php new file mode 100644 index 0000000..2988e83 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/datetime.php @@ -0,0 +1,26 @@ +Hash->extract($row, $field['data_path']); + if (is_array($data)) { + if (count($data) > 1) { + $data = implode(', ', $data); + } else { + if (count($data) > 0) { + $data = $data[0]; + } else { + $data = ''; + } + } + } + $data = h($data); + if (is_numeric($data)) { + $data = date('Y-m-d H:i:s', $data); + } + if (!empty($field['onClick'])) { + $data = sprintf( + '%s', + $field['onClick'], + $data + ); + } + echo $data; +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/distribution_levels.php b/app/templates/element/genericElements/IndexTable/Fields/distribution_levels.php new file mode 100644 index 0000000..912ffef --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/distribution_levels.php @@ -0,0 +1,15 @@ +Hash->extract($row, $field['data_path'])[0]); + echo sprintf( + '%s', + $distributionLevel == 0 ? 'red' : '', + $distributionLevel != 4 ? $distributionLevels[$distributionLevel] : + sprintf( + '%s', + $baseurl, + h($row['SharingGroup']['id']), + h($row['SharingGroup']['name']) + ) + ); + +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/generic_field.php b/app/templates/element/genericElements/IndexTable/Fields/generic_field.php new file mode 100644 index 0000000..afdcfc0 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/generic_field.php @@ -0,0 +1,37 @@ +Hash->extract($row, $field['data_path']); + if (is_array($data)) { + if (count($data) > 1) { + $data = implode(', ', $data); + } else { + if (count($data) > 0) { + $data = $data[0]; + } else { + $data = ''; + } + } + } + if (is_bool($data)) { + $data = sprintf( + '', + $data ? 'check' : 'times' + ); + $data = ''; + } else { + $data = h($data); + if (!empty($field['privacy'])) { + $data = sprintf( + '**************************************** ', + $data + ); + } + } + if (!empty($field['onClick'])) { + $data = sprintf( + '%s', + $field['onClick'], + $data + ); + } + echo $data; +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/icon.php b/app/templates/element/genericElements/IndexTable/Fields/icon.php new file mode 100644 index 0000000..4f724f8 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/icon.php @@ -0,0 +1,5 @@ +', + $this->FontAwesome->getClass($this->Hash->extract($row, $field['data_path'])[0]) +); \ No newline at end of file diff --git a/app/templates/element/genericElements/IndexTable/Fields/json.php b/app/templates/element/genericElements/IndexTable/Fields/json.php new file mode 100644 index 0000000..6c14248 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/json.php @@ -0,0 +1,16 @@ +Hash->extract($row, $field['data_path'])); + // I feed dirty for this... + if (is_array($data) && count($data) === 1 && isset($data[0])) { + $data = $data[0]; + } + echo sprintf( + '
    ', + h($k) + ); +?> + diff --git a/app/templates/element/genericElements/IndexTable/Fields/links.php b/app/templates/element/genericElements/IndexTable/Fields/links.php new file mode 100644 index 0000000..7953d2f --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/links.php @@ -0,0 +1,47 @@ +Hash->extract($row, $field['data_path']); + $url_param_data_paths = ''; + $urlWithData = empty($field['url']) ? '#' : h($field['url']); + if (!empty($field['url_params_data_paths'])) { + if (is_array($field['url_params_data_paths'])) { + $temp = array(); + foreach ($field['url_params_data_paths'] as $path) { + $temp[] = h($this->Hash->extract($row, $path)[0]); + } + $url_param_data_paths = implode('/', $temp); + } else { + $url_param_data_paths = h($this->Hash->extract($row, $field['url_params_data_paths'])[0]); + } + $urlWithData .= '/' . $url_param_data_paths; + } + $links = array(); + foreach ($data_elements as $data) { + if (!empty($data['name'])) { + $field['title'] = $data['name']; + } + if (!empty($data['url'])) { + $data = $data['url']; + } + if (isset($field['url']) && strpos($field['url'], '%s') !== false) { + $url = sprintf( + $field['url'], + $data + ); + } elseif (!empty($field['url_params_data_paths'])) { + $url = $urlWithData; + } else { + $url = $data; + } + $links[] = sprintf( + '%s', + h($url), + empty($field['title']) ? h($data) : h($field['title']), + empty($field['title']) ? h($data) : h($field['title']) + ); + } + echo implode('
    ', $links); +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/list.php b/app/templates/element/genericElements/IndexTable/Fields/list.php new file mode 100644 index 0000000..a524dc8 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/list.php @@ -0,0 +1,16 @@ +Hash->extract($row, $field['data_path']); + foreach ($data as $key => $element) { + if (!is_numeric($key)) { + $data[$key] = sprintf( + '%s: %s', + h($key), + h($element) + ); + } else { + $data[$key] = h($element); + } + } + $data = implode('
    ', $data); + echo $data; +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/org.php b/app/templates/element/genericElements/IndexTable/Fields/org.php new file mode 100644 index 0000000..7243d3b --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/org.php @@ -0,0 +1,38 @@ +Hash->extract($row, $field['data_path']); + if (!isset($field['fields']['allow_picture'])) { + $field['fields']['allow_picture'] = true; + } + if (!isset($field['fields']['default_org'])) { + $field['fields']['default_org'] = ''; + } + if (!empty($orgs)) { + if (!isset($orgs[0])) { + $orgs = array($orgs); + } + $count = count($orgs); + $i = 0; + foreach ($orgs as $org) { + $i++; + if (!empty($org['id']) || !empty($org['name'])) { + if ($field['fields']['allow_picture'] && !empty($org['id'])) { + echo $this->OrgImg->getOrgImg(array('name' => $org['name'], 'id' => $org['id'], 'size' => 24)); + } else { + echo sprintf( + '%s', + $baseurl, + empty($org['id']) ? h($org['uuid']) : h($org['id']), + h($org['name']) + ); + } + if ($i < $count) { + echo '
    '; + } + } else { + if ($field['fields']['allow_picture']) { + echo $this->OrgImg->getOrgImg(array('name' => $field['fields']['default_org'], 'size' => 24)); + } + } + } + } +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/role.php b/app/templates/element/genericElements/IndexTable/Fields/role.php new file mode 100644 index 0000000..377dfef --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/role.php @@ -0,0 +1,22 @@ +Hash->extract($row, $field['data_path']); + if (!empty($roles)) { + if (!isset($roles[0])) { + $roles = array($roles); + } + $count = count($roles); + $i = 0; + foreach ($roles as $role) { + $i++; + echo sprintf( + '%s', + $baseurl, + h($role['id']), + h($role['name']) + ); + if ($i < $count) { + echo '
    '; + } + } + } +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/selector.php b/app/templates/element/genericElements/IndexTable/Fields/selector.php new file mode 100644 index 0000000..f7c6530 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/selector.php @@ -0,0 +1,20 @@ + $dataValue) { + $value = ''; + if (!empty($dataValue['value'])) { + $value = $dataValue['value']; + } + if (!empty($dataValue['value_path']) && !empty($this->Hash->extract($row, $dataValue['value_path'])[0])) { + $value = $this->Hash->extract($row, $dataValue['value_path'])[0]; + } + $data[] = 'data-' . h($dataField) . '="' . h($value) . '"'; + } + } + echo sprintf( + '', + h($k), + empty($data) ? '' : implode(' ', $data) + ); +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/self_registration.php b/app/templates/element/genericElements/IndexTable/Fields/self_registration.php new file mode 100644 index 0000000..44efff9 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/self_registration.php @@ -0,0 +1,17 @@ +Hash->extract($row, $field['data_path_requirement']); + if (empty($self_registration_flag[0])) { + echo ''; + } else { + $url = $this->Hash->extract($row, $field['data_path'])[0]; + echo sprintf( + '%s', + (!empty($self_registration_flag[0])) ? 'check' : 'times', + (empty($self_registration_flag[0])) ? '' : + sprintf( + ' (' . __('click here') . ')', + h($url) + ) + ); + } +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/sparkline.php b/app/templates/element/genericElements/IndexTable/Fields/sparkline.php new file mode 100644 index 0000000..0119093 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/sparkline.php @@ -0,0 +1,4 @@ +Hash->extract($row, $field['data_path'])[0]; + echo $this->element('sparkline', array('scope' => $field['csv']['scope'], 'id' => $elementId, 'csv' => $field['csv']['data'][$k])); +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/tags.php b/app/templates/element/genericElements/IndexTable/Fields/tags.php new file mode 100644 index 0000000..b3dd0d8 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/tags.php @@ -0,0 +1,17 @@ +Hash->extract($row, $field['data_path']); + if (!empty($tags)) { + if (empty($tags[0])) { + $tags = array($tags); + } + echo $this->element( + 'ajaxTags', + array( + 'attributeId' => 0, + 'tags' => $tags, + 'tagAccess' => false, + 'static_tags_only' => 1 + ) + ); + } +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/target_event.php b/app/templates/element/genericElements/IndexTable/Fields/target_event.php new file mode 100644 index 0000000..0422c88 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/target_event.php @@ -0,0 +1,33 @@ +DataPathCollector->extract($row, $field['data_path']); + if ($data['Feed.enabled']) { + if (in_array($data['Feed.source_format'], array('freetext', 'csv'))) { + if ($data['Feed.fixed_event']) { + if (!empty($data['Feed.event_error'])) { + echo sprintf( + '%s', + __('Error: Invalid event!') + ); + } else { + if ($data['Feed.event_id']) { + echo sprintf( + '%s', + $baseurl, + h($data['Feed.event_id']), + __('Fixed event %s', h($data['Feed.event_id'])) + ); + } else { + echo __('New fixed event'); + } + } + } else { + echo sprintf( + '%s', + __('New event each pull can lead to potentially endlessly growing correlation tables. Only use this setting if you are sure that the data in the feed will mostly be completely distinct between each individual pull, otherwise use fixed events. Generally this setting is NOT recommended.'), + __('New event each pull') + ); + } + } + } else { + echo __('Feed not enabled'); + } diff --git a/app/templates/element/genericElements/IndexTable/Fields/tester.php b/app/templates/element/genericElements/IndexTable/Fields/tester.php new file mode 100644 index 0000000..d6447cf --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/tester.php @@ -0,0 +1,30 @@ +
    %s
    ', + h($k), + h($column), + empty($field['textInput']) ? '' : sprintf( + '', + h($k), + h($column) + ), + !empty($field['button_class']) ? $field['button_class'] : 'btn-inverse', + empty($field['button_icon']) ? '' : $this->FontAwesome->getClass($field['button_icon']) . ' white', + !empty($field['button_style']) ? $field['button_style'] : 'line-height:20px;', + empty($field['textInput']) ? '' : 'border-radius: 0px 3px 3px 0px;', + empty($field['url']) ? '' : sprintf( + 'onClick="runOnDemandAction(this, \'%s%s\', \'onDemandButtonResult%s-%s\', \'%s\');"', + h($field['url']), + h($this->Hash->extract($row, $field['data_path'])[0]), + h($k), + h($column), + empty($field['textInput']) ? '' : sprintf( + 'onDemandTextEntry%s-%s', + h($k), + h($column) + ) + ), + !empty($field['button']) ? h($field['button']) : '' + ); + +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/timestamp.php b/app/templates/element/genericElements/IndexTable/Fields/timestamp.php new file mode 100644 index 0000000..5916178 --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/timestamp.php @@ -0,0 +1,7 @@ +Hash->extract($row, $field['data_path'])[0]; + if (!empty($field['time_format'])) { + $timestamp = date($field['time_format'], $timestamp); + } + echo h($timestamp); +?> diff --git a/app/templates/element/genericElements/IndexTable/Fields/toggle.php b/app/templates/element/genericElements/IndexTable/Fields/toggle.php new file mode 100644 index 0000000..cd17d9d --- /dev/null +++ b/app/templates/element/genericElements/IndexTable/Fields/toggle.php @@ -0,0 +1,59 @@ +Hash->extract($row, $field['data_path']); + $seed = rand(); + $checkboxId = 'GenericToggle-' . $seed; + $tempboxId = 'TempBox-' . $seed; + echo sprintf( + '