diff --git a/.gitignore b/.gitignore index 2729c73bd..f64f1a3d8 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ node_modules test_shared/ **/cache/ storage/ +phpunit.xml diff --git a/composer.json b/composer.json index 25714d395..144aaa1ba 100644 --- a/composer.json +++ b/composer.json @@ -31,27 +31,29 @@ "laravel/framework": "5.4.*", "luracast/restler": "^3.0", "bshaffer/oauth2-server-php": "v1.0", - "colosa/pmUI": "release/3.2.4-dev", - "colosa/MichelangeloFE": "release/3.2.4-dev", - "colosa/pmdynaform": "release/3.2.4-dev", + "colosa/pmUI": "release/3.3.1-dev", + "colosa/MichelangeloFE": "release/3.3.1-dev", + "colosa/pmdynaform": "release/3.3.1-dev", "google/apiclient": "1.1.6", "dapphp/securimage": "^3.6", "psr/log": "1.0.0", "monolog/monolog": "1.19.0", "geshi/geshi": "dev-master", "libchart/libchart": "1.4.0", - "phpmailer/phpmailer": "5.2.4", + "phpmailer/phpmailer": "5.2.27", "pear/archive_tar": "1.4.*", "pear/console_getopt": "1.4.*", "TYPO3/class-alias-loader": "^1.0", "ralouphie/getallheaders": "^2.0", "smarty/smarty": "2.6.30", "pdepend/pdepend": "@stable", - "chumper/zipper": "^1.0" + "chumper/zipper": "^1.0", + "nikic/php-parser": "3.1.5", + "laravel/tinker": "^1.0" }, "require-dev": { "fzaninotto/faker": "^1.7", - "guzzle/guzzle": "~3.1.1", + "guzzlehttp/guzzle": "^6.3", "phpunit/phpunit": "~5.7", "lmc/steward": "^2.2", "behat/behat": "^3.3", diff --git a/composer.lock b/composer.lock index 8cf93aa42..c56712f71 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0a979177bf17fe938d96211e6a03cc21", + "content-hash": "a9ba65f7fb68be7c36dd45b62216b2c6", "packages": [ { "name": "bshaffer/oauth2-server-php", @@ -29,7 +29,7 @@ "OAuth2": "src/" } }, - "notification-url": "http://packagist.org/downloads/", + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -111,14 +111,14 @@ }, { "name": "colosa/MichelangeloFE", - "version": "dev-release/3.2.4", + "version": "dev-release/3.3.1", "source": { "type": "git", "url": "git@bitbucket.org:colosa/michelangelofe.git", - "reference": "1780c624132004aa13d80882937f61527adafad5" + "reference": "4ac7ac3ebd1863c258c3f0e048fd3fff668f0184" }, "require": { - "colosa/pmui": "release/3.2.4-dev" + "colosa/pmui": "release/3.3.1-dev" }, "type": "library", "description": "ProcessMaker Michelangelo Front End", @@ -126,15 +126,15 @@ "keywords": [ "js app ProcessMaker" ], - "time": "2018-05-04T18:33:23+00:00" + "time": "2018-11-29T15:23:08+00:00" }, { "name": "colosa/pmDynaform", - "version": "dev-release/3.2.4", + "version": "dev-release/3.3.1", "source": { "type": "git", "url": "git@bitbucket.org:colosa/pmdynaform.git", - "reference": "d22d2d185cac311fb803e0b6891160804091bac1" + "reference": "e4176c9772842904552997702e549035b6ba641d" }, "type": "library", "description": "JS Library to render ProcessMaker Dynaforms", @@ -142,15 +142,15 @@ "keywords": [ "js lib ProcessMaker Dynaforms" ], - "time": "2018-04-23T18:36:59+00:00" + "time": "2018-11-28T17:54:53+00:00" }, { "name": "colosa/pmUI", - "version": "dev-release/3.2.4", + "version": "dev-release/3.3.1", "source": { "type": "git", "url": "git@bitbucket.org:colosa/pmui.git", - "reference": "583402fdb1a5da606d02cc25f4a5573c3ff800b2" + "reference": "711b9796c7b5ad4363b9177d0969ec4abecc8d2e" }, "type": "library", "description": "JS UI Library", @@ -158,7 +158,7 @@ "keywords": [ "js lib ProcessMaker UI" ], - "time": "2018-04-19T20:17:00+00:00" + "time": "2018-11-16T14:26:15+00:00" }, { "name": "dapphp/securimage", @@ -209,6 +209,39 @@ ], "time": "2018-03-09T06:07:41+00:00" }, + { + "name": "dnoegel/php-xdg-base-dir", + "version": "0.1", + "source": { + "type": "git", + "url": "https://github.com/dnoegel/php-xdg-base-dir.git", + "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/265b8593498b997dc2d31e75b89f053b5cc9621a", + "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "@stable" + }, + "type": "project", + "autoload": { + "psr-4": { + "XdgBaseDir\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "implementation of xdg base directory specification for php", + "time": "2014-10-24T07:27:01+00:00" + }, { "name": "doctrine/inflector", "version": "v1.1.0", @@ -328,12 +361,12 @@ "source": { "type": "git", "url": "https://github.com/GeSHi/geshi-1.0.git", - "reference": "ed9f49a7c7a195f6ed2bc864f5ce03b990b5867d" + "reference": "5861c58981244ab6ee0dd337f096ff14bf15b1eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GeSHi/geshi-1.0/zipball/ed9f49a7c7a195f6ed2bc864f5ce03b990b5867d", - "reference": "ed9f49a7c7a195f6ed2bc864f5ce03b990b5867d", + "url": "https://api.github.com/repos/GeSHi/geshi-1.0/zipball/5861c58981244ab6ee0dd337f096ff14bf15b1eb", + "reference": "5861c58981244ab6ee0dd337f096ff14bf15b1eb", "shasum": "" }, "require-dev": { @@ -360,19 +393,19 @@ ], "description": "Generic Syntax Highlighter", "homepage": "http://qbnz.com/highlighter/", - "time": "2018-03-09T20:04:39+00:00" + "time": "2018-10-01T23:49:06+00:00" }, { "name": "google/apiclient", "version": "1.1.6", "source": { "type": "git", - "url": "https://github.com/google/google-api-php-client.git", + "url": "https://github.com/googleapis/google-api-php-client.git", "reference": "a25dc9d5c109ebb02945ba1ff6336cc937c27628" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/google/google-api-php-client/zipball/a25dc9d5c109ebb02945ba1ff6336cc937c27628", + "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/a25dc9d5c109ebb02945ba1ff6336cc937c27628", "reference": "a25dc9d5c109ebb02945ba1ff6336cc937c27628", "shasum": "" }, @@ -405,6 +438,94 @@ ], "time": "2015-10-16T22:11:08+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": "laravel/framework", "version": "v5.4.36", @@ -535,29 +656,92 @@ "time": "2017-08-30T09:26:16+00:00" }, { - "name": "league/flysystem", - "version": "1.0.45", + "name": "laravel/tinker", + "version": "v1.0.8", "source": { "type": "git", - "url": "https://github.com/thephpleague/flysystem.git", - "reference": "a99f94e63b512d75f851b181afcdf0ee9ebef7e6" + "url": "https://github.com/laravel/tinker.git", + "reference": "cafbf598a90acde68985660e79b2b03c5609a405" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a99f94e63b512d75f851b181afcdf0ee9ebef7e6", - "reference": "a99f94e63b512d75f851b181afcdf0ee9ebef7e6", + "url": "https://api.github.com/repos/laravel/tinker/zipball/cafbf598a90acde68985660e79b2b03c5609a405", + "reference": "cafbf598a90acde68985660e79b2b03c5609a405", "shasum": "" }, "require": { + "illuminate/console": "~5.1", + "illuminate/contracts": "~5.1", + "illuminate/support": "~5.1", + "php": ">=5.5.9", + "psy/psysh": "0.7.*|0.8.*|0.9.*", + "symfony/var-dumper": "~3.0|~4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0|~5.0" + }, + "suggest": { + "illuminate/database": "The Illuminate Database package (~5.1)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + }, + "laravel": { + "providers": [ + "Laravel\\Tinker\\TinkerServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Tinker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Powerful REPL for the Laravel framework.", + "keywords": [ + "REPL", + "Tinker", + "laravel", + "psysh" + ], + "time": "2018-10-12T19:39:35+00:00" + }, + { + "name": "league/flysystem", + "version": "1.0.49", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "a63cc83d8a931b271be45148fa39ba7156782ffd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a63cc83d8a931b271be45148fa39ba7156782ffd", + "reference": "a63cc83d8a931b271be45148fa39ba7156782ffd", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", "php": ">=5.5.9" }, "conflict": { "league/flysystem-sftp": "<1.0.6" }, "require-dev": { - "ext-fileinfo": "*", "phpspec/phpspec": "^3.4", - "phpunit/phpunit": "^5.7" + "phpunit/phpunit": "^5.7.10" }, "suggest": { "ext-fileinfo": "Required for MimeType", @@ -616,7 +800,7 @@ "sftp", "storage" ], - "time": "2018-05-07T08:44:23+00:00" + "time": "2018-11-23T23:41:29+00:00" }, { "name": "libchart/libchart", @@ -867,16 +1051,16 @@ }, { "name": "nesbot/carbon", - "version": "1.27.0", + "version": "1.36.1", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "ef81c39b67200dcd7401c24363dcac05ac3a4fe9" + "reference": "63da8cdf89d7a5efe43aabc794365f6e7b7b8983" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/ef81c39b67200dcd7401c24363dcac05ac3a4fe9", - "reference": "ef81c39b67200dcd7401c24363dcac05ac3a4fe9", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/63da8cdf89d7a5efe43aabc794365f6e7b7b8983", + "reference": "63da8cdf89d7a5efe43aabc794365f6e7b7b8983", "shasum": "" }, "require": { @@ -884,10 +1068,20 @@ "symfony/translation": "~2.6 || ~3.0 || ~4.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "~2", "phpunit/phpunit": "^4.8.35 || ^5.7" }, + "suggest": { + "friendsofphp/php-cs-fixer": "Needed for the `composer phpcs` command. Allow to automatically fix code style.", + "phpstan/phpstan": "Needed for the `composer phpstan` command. Allow to detect potential errors." + }, "type": "library", + "extra": { + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + } + }, "autoload": { "psr-4": { "": "src/" @@ -911,20 +1105,71 @@ "datetime", "time" ], - "time": "2018-04-23T09:02:57+00:00" + "time": "2018-11-22T18:23:02+00:00" }, { - "name": "paragonie/random_compat", - "version": "v2.0.12", + "name": "nikic/php-parser", + "version": "v3.1.5", "source": { "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb" + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "bb87e28e7d7b8d9a7fda231d37457c9210faf6ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/258c89a6b97de7dfaf5b8c7607d0478e236b04fb", - "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bb87e28e7d7b8d9a7fda231d37457c9210faf6ce", + "reference": "bb87e28e7d7b8d9a7fda231d37457c9210faf6ce", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "~4.0|~5.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-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": "2018-02-28T20:30:58+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v2.0.17", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/29af24f25bab834fcbb38ad2a69fa93b867e070d", + "reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d", "shasum": "" }, "require": { @@ -956,10 +1201,11 @@ "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", "keywords": [ "csprng", + "polyfill", "pseudorandom", "random" ], - "time": "2018-04-04T21:24:14+00:00" + "time": "2018-07-04T16:31:37+00:00" }, { "name": "pdepend/pdepend", @@ -1116,20 +1362,20 @@ }, { "name": "pear/pear-core-minimal", - "version": "v1.10.3", + "version": "v1.10.6", "source": { "type": "git", "url": "https://github.com/pear/pear-core-minimal.git", - "reference": "070f0b600b2caca2501e2c9b7e553016e4b0d115" + "reference": "052868b244d31f822796e7e9981f62557eb256d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pear/pear-core-minimal/zipball/070f0b600b2caca2501e2c9b7e553016e4b0d115", - "reference": "070f0b600b2caca2501e2c9b7e553016e4b0d115", + "url": "https://api.github.com/repos/pear/pear-core-minimal/zipball/052868b244d31f822796e7e9981f62557eb256d4", + "reference": "052868b244d31f822796e7e9981f62557eb256d4", "shasum": "" }, "require": { - "pear/console_getopt": "~1.4", + "pear/console_getopt": "~1.3", "pear/pear_exception": "~1.0" }, "replace": { @@ -1156,7 +1402,7 @@ } ], "description": "Minimal set of PEAR core files to be used as composer dependency", - "time": "2017-02-28T16:46:11+00:00" + "time": "2018-08-22T19:28:09+00:00" }, { "name": "pear/pear_exception", @@ -1215,31 +1461,55 @@ }, { "name": "phpmailer/phpmailer", - "version": "v5.2.4", + "version": "v5.2.27", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "adb0197c106fad05c1fab28dbed5437133836c44" + "reference": "dde1db116511aa4956389d75546c5be4c2beb2a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/adb0197c106fad05c1fab28dbed5437133836c44", - "reference": "adb0197c106fad05c1fab28dbed5437133836c44", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/dde1db116511aa4956389d75546c5be4c2beb2a6", + "reference": "dde1db116511aa4956389d75546c5be4c2beb2a6", "shasum": "" }, "require": { + "ext-ctype": "*", "php": ">=5.0.0" }, "require-dev": { - "phpdocumentor/phpdocumentor": "*", - "phpunit/phpunit": "*" + "doctrine/annotations": "1.2.*", + "jms/serializer": "0.16.*", + "phpdocumentor/phpdocumentor": "2.*", + "phpunit/phpunit": "4.8.*", + "symfony/debug": "2.8.*", + "symfony/filesystem": "2.8.*", + "symfony/translation": "2.8.*", + "symfony/yaml": "2.8.*", + "zendframework/zend-cache": "2.5.1", + "zendframework/zend-config": "2.5.1", + "zendframework/zend-eventmanager": "2.5.1", + "zendframework/zend-filter": "2.5.1", + "zendframework/zend-i18n": "2.5.1", + "zendframework/zend-json": "2.5.1", + "zendframework/zend-math": "2.5.1", + "zendframework/zend-serializer": "2.5.*", + "zendframework/zend-servicemanager": "2.5.*", + "zendframework/zend-stdlib": "2.5.1" + }, + "suggest": { + "league/oauth2-google": "Needed for Google XOAUTH2 authentication" }, "type": "library", "autoload": { "classmap": [ "class.phpmailer.php", + "class.phpmaileroauth.php", + "class.phpmaileroauthgoogle.php", + "class.smtp.php", "class.pop3.php", - "class.smtp.php" + "extras/EasyPeasyICS.php", + "extras/ntlm_sasl_client.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1264,7 +1534,7 @@ } ], "description": "PHPMailer is a full-featured email creation and transfer class for PHP", - "time": "2013-02-21T11:44:28+00:00" + "time": "2017-11-04T09:26:05+00:00" }, { "name": "psr/container", @@ -1353,6 +1623,80 @@ ], "time": "2012-12-21T11:40:51+00:00" }, + { + "name": "psy/psysh", + "version": "v0.9.9", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "9aaf29575bb8293206bb0420c1e1c87ff2ffa94e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/9aaf29575bb8293206bb0420c1e1c87ff2ffa94e", + "reference": "9aaf29575bb8293206bb0420c1e1c87ff2ffa94e", + "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", + "symfony/var-dumper": "~2.7|~3.0|~4.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": "2018-10-13T15:16:03+00:00" + }, { "name": "ralouphie/getallheaders", "version": "2.0.5", @@ -1395,21 +1739,22 @@ }, { "name": "ramsey/uuid", - "version": "3.7.3", + "version": "3.8.0", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "44abcdad877d9a46685a3a4d221e3b2c4b87cb76" + "reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/44abcdad877d9a46685a3a4d221e3b2c4b87cb76", - "reference": "44abcdad877d9a46685a3a4d221e3b2c4b87cb76", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/d09ea80159c1929d75b3f9c60504d613aeb4a1e3", + "reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3", "shasum": "" }, "require": { - "paragonie/random_compat": "^1.0|^2.0", - "php": "^5.4 || ^7.0" + "paragonie/random_compat": "^1.0|^2.0|9.99.99", + "php": "^5.4 || ^7.0", + "symfony/polyfill-ctype": "^1.8" }, "replace": { "rhumsaa/uuid": "self.version" @@ -1417,16 +1762,17 @@ "require-dev": { "codeception/aspect-mock": "^1.0 | ~2.0.0", "doctrine/annotations": "~1.2.0", - "goaop/framework": "1.0.0-alpha.2 | ^1.0 | ^2.1", + "goaop/framework": "1.0.0-alpha.2 | ^1.0 | ~2.1.0", "ircmaxell/random-lib": "^1.1", "jakub-onderka/php-parallel-lint": "^0.9.0", "mockery/mockery": "^0.9.9", "moontoast/math": "^1.1", "php-mock/php-mock-phpunit": "^0.3|^1.1", - "phpunit/phpunit": "^4.7|^5.0", + "phpunit/phpunit": "^4.7|^5.0|^6.5", "squizlabs/php_codesniffer": "^2.3" }, "suggest": { + "ext-ctype": "Provides support for PHP Ctype functions", "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", @@ -1471,7 +1817,7 @@ "identifier", "uuid" ], - "time": "2018-01-20T00:28:24+00:00" + "time": "2018-07-19T23:38:55+00:00" }, { "name": "smarty/smarty", @@ -1526,16 +1872,16 @@ }, { "name": "swiftmailer/swiftmailer", - "version": "v5.4.9", + "version": "v5.4.12", "source": { "type": "git", "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "7ffc1ea296ed14bf8260b6ef11b80208dbadba91" + "reference": "181b89f18a90f8925ef805f950d47a7190e9b950" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/7ffc1ea296ed14bf8260b6ef11b80208dbadba91", - "reference": "7ffc1ea296ed14bf8260b6ef11b80208dbadba91", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/181b89f18a90f8925ef805f950d47a7190e9b950", + "reference": "181b89f18a90f8925ef805f950d47a7190e9b950", "shasum": "" }, "require": { @@ -1576,25 +1922,26 @@ "mail", "mailer" ], - "time": "2018-01-23T07:37:21+00:00" + "time": "2018-07-31T09:26:32+00:00" }, { "name": "symfony/config", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "7c2a9d44f4433863e9bca682e7f03609234657f9" + "reference": "8a660daeb65dedbe0b099529f65e61866c055081" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/7c2a9d44f4433863e9bca682e7f03609234657f9", - "reference": "7c2a9d44f4433863e9bca682e7f03609234657f9", + "url": "https://api.github.com/repos/symfony/config/zipball/8a660daeb65dedbe0b099529f65e61866c055081", + "reference": "8a660daeb65dedbe0b099529f65e61866c055081", "shasum": "" }, "require": { "php": "^5.5.9|>=7.0.8", - "symfony/filesystem": "~2.8|~3.0|~4.0" + "symfony/filesystem": "~2.8|~3.0|~4.0", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { "symfony/dependency-injection": "<3.3", @@ -1639,20 +1986,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2018-03-19T22:32:39+00:00" + "time": "2018-11-26T10:17:44+00:00" }, { "name": "symfony/console", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "5b1fdfa8eb93464bcc36c34da39cedffef822cdf" + "reference": "8f80fc39bbc3b7c47ee54ba7aa2653521ace94bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/5b1fdfa8eb93464bcc36c34da39cedffef822cdf", - "reference": "5b1fdfa8eb93464bcc36c34da39cedffef822cdf", + "url": "https://api.github.com/repos/symfony/console/zipball/8f80fc39bbc3b7c47ee54ba7aa2653521ace94bb", + "reference": "8f80fc39bbc3b7c47ee54ba7aa2653521ace94bb", "shasum": "" }, "require": { @@ -1708,20 +2055,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-04-30T01:22:56+00:00" + "time": "2018-11-26T12:48:07+00:00" }, { "name": "symfony/css-selector", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "519a80d7c1d95c6cc0b67f686d15fe27c6910de0" + "reference": "345b9a48595d1ab9630db791dbc3e721bf0233e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/519a80d7c1d95c6cc0b67f686d15fe27c6910de0", - "reference": "519a80d7c1d95c6cc0b67f686d15fe27c6910de0", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/345b9a48595d1ab9630db791dbc3e721bf0233e8", + "reference": "345b9a48595d1ab9630db791dbc3e721bf0233e8", "shasum": "" }, "require": { @@ -1747,7 +2094,7 @@ ], "authors": [ { - "name": "Jean-Fran?ois Simon", + "name": "Jean-François Simon", "email": "jeanfrancois.simon@sensiolabs.com" }, { @@ -1761,20 +2108,20 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2018-03-19T22:32:39+00:00" + "time": "2018-11-11T19:48:54+00:00" }, { "name": "symfony/debug", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "1b95888cfd996484527cb41e8952d9a5eaf7454f" + "reference": "2016b3eec2e49c127dd02d0ef44a35c53181560d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/1b95888cfd996484527cb41e8952d9a5eaf7454f", - "reference": "1b95888cfd996484527cb41e8952d9a5eaf7454f", + "url": "https://api.github.com/repos/symfony/debug/zipball/2016b3eec2e49c127dd02d0ef44a35c53181560d", + "reference": "2016b3eec2e49c127dd02d0ef44a35c53181560d", "shasum": "" }, "require": { @@ -1817,20 +2164,20 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2018-04-30T16:53:52+00:00" + "time": "2018-11-11T19:48:54+00:00" }, { "name": "symfony/dependency-injection", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "54ff9d78b56429f9a1ac12e60bfb6d169c0468e3" + "reference": "622b330ced1bdf29d240bd1c364c038f647eb0f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/54ff9d78b56429f9a1ac12e60bfb6d169c0468e3", - "reference": "54ff9d78b56429f9a1ac12e60bfb6d169c0468e3", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/622b330ced1bdf29d240bd1c364c038f647eb0f5", + "reference": "622b330ced1bdf29d240bd1c364c038f647eb0f5", "shasum": "" }, "require": { @@ -1888,20 +2235,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2018-04-29T14:04:08+00:00" + "time": "2018-11-20T16:14:23+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "fdd5abcebd1061ec647089c6c41a07ed60af09f8" + "reference": "d365fc4416ec4980825873962ea5d1b1bca46f1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/fdd5abcebd1061ec647089c6c41a07ed60af09f8", - "reference": "fdd5abcebd1061ec647089c6c41a07ed60af09f8", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d365fc4416ec4980825873962ea5d1b1bca46f1a", + "reference": "d365fc4416ec4980825873962ea5d1b1bca46f1a", "shasum": "" }, "require": { @@ -1951,24 +2298,25 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2018-04-06T07:35:25+00:00" + "time": "2018-11-26T10:17:44+00:00" }, { "name": "symfony/filesystem", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "253a4490b528597aa14d2bf5aeded6f5e5e4a541" + "reference": "b49b1ca166bd109900e6a1683d9bb1115727ef2d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/253a4490b528597aa14d2bf5aeded6f5e5e4a541", - "reference": "253a4490b528597aa14d2bf5aeded6f5e5e4a541", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/b49b1ca166bd109900e6a1683d9bb1115727ef2d", + "reference": "b49b1ca166bd109900e6a1683d9bb1115727ef2d", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-ctype": "~1.8" }, "type": "library", "extra": { @@ -2000,20 +2348,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2018-02-22T10:48:49+00:00" + "time": "2018-11-11T19:48:54+00:00" }, { "name": "symfony/finder", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "bd14efe8b1fabc4de82bf50dce62f05f9a102433" + "reference": "6cf2be5cbd0e87aa35c01f80ae0bf40b6798e442" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/bd14efe8b1fabc4de82bf50dce62f05f9a102433", - "reference": "bd14efe8b1fabc4de82bf50dce62f05f9a102433", + "url": "https://api.github.com/repos/symfony/finder/zipball/6cf2be5cbd0e87aa35c01f80ae0bf40b6798e442", + "reference": "6cf2be5cbd0e87aa35c01f80ae0bf40b6798e442", "shasum": "" }, "require": { @@ -2049,20 +2397,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-04-04T05:07:11+00:00" + "time": "2018-11-11T19:48:54+00:00" }, { "name": "symfony/http-foundation", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "edc43b1a50402bb06b5111eb86b275c87a93e373" + "reference": "ea61dd57c4399b0b2a4162e1820cd9d0783acd38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/edc43b1a50402bb06b5111eb86b275c87a93e373", - "reference": "edc43b1a50402bb06b5111eb86b275c87a93e373", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ea61dd57c4399b0b2a4162e1820cd9d0783acd38", + "reference": "ea61dd57c4399b0b2a4162e1820cd9d0783acd38", "shasum": "" }, "require": { @@ -2103,20 +2451,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2018-04-30T01:05:13+00:00" + "time": "2018-11-26T10:17:44+00:00" }, { "name": "symfony/http-kernel", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "280fcedbcb3dabcc467a9c1734054af61928fe4f" + "reference": "78528325d90e5ad54a6e9eca750fe176932bc4fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/280fcedbcb3dabcc467a9c1734054af61928fe4f", - "reference": "280fcedbcb3dabcc467a9c1734054af61928fe4f", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/78528325d90e5ad54a6e9eca750fe176932bc4fa", + "reference": "78528325d90e5ad54a6e9eca750fe176932bc4fa", "shasum": "" }, "require": { @@ -2124,11 +2472,12 @@ "psr/log": "~1.0", "symfony/debug": "~2.8|~3.0|~4.0", "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/http-foundation": "^3.4.4|^4.0.4" + "symfony/http-foundation": "~3.4.12|~4.0.12|^4.1.1", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { "symfony/config": "<2.8", - "symfony/dependency-injection": "<3.4.5|<4.0.5,>=4", + "symfony/dependency-injection": "<3.4.10|<4.0.10,>=4", "symfony/var-dumper": "<3.3", "twig/twig": "<1.34|<2.4,>=2" }, @@ -2142,7 +2491,7 @@ "symfony/config": "~2.8|~3.0|~4.0", "symfony/console": "~2.8|~3.0|~4.0", "symfony/css-selector": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "^3.4.5|^4.0.5", + "symfony/dependency-injection": "^3.4.10|^4.0.10", "symfony/dom-crawler": "~2.8|~3.0|~4.0", "symfony/expression-language": "~2.8|~3.0|~4.0", "symfony/finder": "~2.8|~3.0|~4.0", @@ -2191,20 +2540,78 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2018-04-30T19:27:02+00:00" + "time": "2018-11-26T14:04:48+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.8.0", + "name": "symfony/polyfill-ctype", + "version": "v1.10.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "3296adf6a6454a050679cde90f95350ad604b171" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171", - "reference": "3296adf6a6454a050679cde90f95350ad604b171", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", + "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + }, + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2018-08-06T14:22:27+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.10.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", + "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", "shasum": "" }, "require": { @@ -2216,7 +2623,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -2250,30 +2657,30 @@ "portable", "shim" ], - "time": "2018-04-26T10:06:28+00:00" + "time": "2018-09-21T13:07:52+00:00" }, { "name": "symfony/polyfill-php70", - "version": "v1.8.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "77454693d8f10dd23bb24955cffd2d82db1007a6" + "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/77454693d8f10dd23bb24955cffd2d82db1007a6", - "reference": "77454693d8f10dd23bb24955cffd2d82db1007a6", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/6b88000cdd431cd2e940caa2cb569201f3f84224", + "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224", "shasum": "" }, "require": { - "paragonie/random_compat": "~1.0|~2.0", + "paragonie/random_compat": "~1.0|~2.0|~9.99", "php": ">=5.3.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -2309,20 +2716,20 @@ "portable", "shim" ], - "time": "2018-04-26T10:06:28+00:00" + "time": "2018-09-21T06:26:08+00:00" }, { "name": "symfony/process", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "4b7d64e852886319e93ddfdecff0d744ab87658b" + "reference": "abb46b909dd6ba0b50e10d4c10ffe6ee96dd70f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/4b7d64e852886319e93ddfdecff0d744ab87658b", - "reference": "4b7d64e852886319e93ddfdecff0d744ab87658b", + "url": "https://api.github.com/repos/symfony/process/zipball/abb46b909dd6ba0b50e10d4c10ffe6ee96dd70f2", + "reference": "abb46b909dd6ba0b50e10d4c10ffe6ee96dd70f2", "shasum": "" }, "require": { @@ -2358,20 +2765,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-04-03T05:22:50+00:00" + "time": "2018-11-20T16:10:26+00:00" }, { "name": "symfony/routing", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "9deb375986f5d1f37283d8386716d26985a0f4b6" + "reference": "86eb1a581279b5e40ca280a4f63a15e37d51d16c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/9deb375986f5d1f37283d8386716d26985a0f4b6", - "reference": "9deb375986f5d1f37283d8386716d26985a0f4b6", + "url": "https://api.github.com/repos/symfony/routing/zipball/86eb1a581279b5e40ca280a4f63a15e37d51d16c", + "reference": "86eb1a581279b5e40ca280a4f63a15e37d51d16c", "shasum": "" }, "require": { @@ -2384,7 +2791,6 @@ }, "require-dev": { "doctrine/annotations": "~1.0", - "doctrine/common": "~2.2", "psr/log": "~1.0", "symfony/config": "^3.3.1|~4.0", "symfony/dependency-injection": "~3.3|~4.0", @@ -2436,20 +2842,20 @@ "uri", "url" ], - "time": "2018-04-12T09:01:03+00:00" + "time": "2018-11-26T08:40:22+00:00" }, { "name": "symfony/translation", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "d4af50f46cd8171fd5c1cdebdb9a8bbcd8078c6c" + "reference": "bdbe940ed3ef4179f86032086c32d3a858becc0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/d4af50f46cd8171fd5c1cdebdb9a8bbcd8078c6c", - "reference": "d4af50f46cd8171fd5c1cdebdb9a8bbcd8078c6c", + "url": "https://api.github.com/repos/symfony/translation/zipball/bdbe940ed3ef4179f86032086c32d3a858becc0f", + "reference": "bdbe940ed3ef4179f86032086c32d3a858becc0f", "shasum": "" }, "require": { @@ -2504,20 +2910,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2018-04-30T01:22:56+00:00" + "time": "2018-11-26T10:17:44+00:00" }, { "name": "symfony/var-dumper", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "0e6545672d8c9ce70dd472adc2f8b03155a46f73" + "reference": "6867713afe6c50ade2f34ed6435563b065a52145" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/0e6545672d8c9ce70dd472adc2f8b03155a46f73", - "reference": "0e6545672d8c9ce70dd472adc2f8b03155a46f73", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6867713afe6c50ade2f34ed6435563b065a52145", + "reference": "6867713afe6c50ade2f34ed6435563b065a52145", "shasum": "" }, "require": { @@ -2573,7 +2979,7 @@ "debug", "dump" ], - "time": "2018-04-26T12:42:15+00:00" + "time": "2018-11-20T16:10:26+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -2624,16 +3030,16 @@ }, { "name": "typo3/class-alias-loader", - "version": "1.0.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/TYPO3/class-alias-loader.git", - "reference": "a9dd295c81ed0b51455644be420ab9210cad688f" + "reference": "4972f9f6c2bad07ab1620b5c9717fa626e9b03b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/TYPO3/class-alias-loader/zipball/a9dd295c81ed0b51455644be420ab9210cad688f", - "reference": "a9dd295c81ed0b51455644be420ab9210cad688f", + "url": "https://api.github.com/repos/TYPO3/class-alias-loader/zipball/4972f9f6c2bad07ab1620b5c9717fa626e9b03b0", + "reference": "4972f9f6c2bad07ab1620b5c9717fa626e9b03b0", "shasum": "" }, "require": { @@ -2646,7 +3052,7 @@ "require-dev": { "composer/composer": "dev-master", "mikey179/vfsstream": "1.4.*@dev", - "phpunit/phpunit": "~4.7.0" + "phpunit/phpunit": "^4.8" }, "type": "composer-plugin", "extra": { @@ -2678,32 +3084,32 @@ "classloader", "composer" ], - "time": "2015-10-06T10:25:44+00:00" + "time": "2018-10-03T12:49:56+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v2.4.0", + "version": "v2.5.1", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c" + "reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", - "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e", + "reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e", "shasum": "" }, "require": { "php": ">=5.3.9" }, "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.0" + "phpunit/phpunit": "^4.8.35 || ^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -2713,7 +3119,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause-Attribution" + "BSD-3-Clause" ], "authors": [ { @@ -2728,22 +3134,22 @@ "env", "environment" ], - "time": "2016-09-01T10:05:43+00:00" + "time": "2018-07-29T20:33:41+00:00" } ], "packages-dev": [ { "name": "beberlei/assert", - "version": "v2.9.5", + "version": "v2.9.6", "source": { "type": "git", "url": "https://github.com/beberlei/assert.git", - "reference": "c07fe163d6a3b3e4b1275981ec004397954afa89" + "reference": "ec9e4cf0b63890edce844ee3922e2b95a526e936" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beberlei/assert/zipball/c07fe163d6a3b3e4b1275981ec004397954afa89", - "reference": "c07fe163d6a3b3e4b1275981ec004397954afa89", + "url": "https://api.github.com/repos/beberlei/assert/zipball/ec9e4cf0b63890edce844ee3922e2b95a526e936", + "reference": "ec9e4cf0b63890edce844ee3922e2b95a526e936", "shasum": "" }, "require": { @@ -2785,20 +3191,20 @@ "assertion", "validation" ], - "time": "2018-04-16T11:18:27+00:00" + "time": "2018-06-11T17:15:25+00:00" }, { "name": "behat/behat", - "version": "v3.4.3", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/Behat/Behat.git", - "reference": "d60b161bff1b95ec4bb80bb8cb210ccf890314c2" + "reference": "e4bce688be0c2029dc1700e46058d86428c63cab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Behat/Behat/zipball/d60b161bff1b95ec4bb80bb8cb210ccf890314c2", - "reference": "d60b161bff1b95ec4bb80bb8cb210ccf890314c2", + "url": "https://api.github.com/repos/Behat/Behat/zipball/e4bce688be0c2029dc1700e46058d86428c63cab", + "reference": "e4bce688be0c2029dc1700e46058d86428c63cab", "shasum": "" }, "require": { @@ -2808,9 +3214,9 @@ "ext-mbstring": "*", "php": ">=5.3.3", "psr/container": "^1.0", - "symfony/class-loader": "~2.1||~3.0||~4.0", + "symfony/class-loader": "~2.1||~3.0", "symfony/config": "~2.3||~3.0||~4.0", - "symfony/console": "~2.5||~3.0||~4.0", + "symfony/console": "~2.7.40||^2.8.33||~3.3.15||^3.4.3||^4.0.3", "symfony/dependency-injection": "~2.1||~3.0||~4.0", "symfony/event-dispatcher": "~2.1||~3.0||~4.0", "symfony/translation": "~2.3||~3.0||~4.0", @@ -2821,18 +3227,13 @@ "phpunit/phpunit": "^4.8.36|^6.3", "symfony/process": "~2.5|~3.0|~4.0" }, - "suggest": { - "behat/mink-extension": "for integration with Mink testing framework", - "behat/symfony2-extension": "for integration with Symfony2 web framework", - "behat/yii-extension": "for integration with Yii web framework" - }, "bin": [ "bin/behat" ], "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2.x-dev" + "dev-master": "3.5.x-dev" } }, "autoload": { @@ -2868,7 +3269,7 @@ "symfony", "testing" ], - "time": "2017-11-27T10:37:56+00:00" + "time": "2018-08-10T18:56:51+00:00" }, { "name": "behat/gherkin", @@ -3224,34 +3625,39 @@ }, { "name": "facebook/webdriver", - "version": "1.5.0", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/facebook/php-webdriver.git", - "reference": "86b5ca2f67173c9d34340845dd690149c886a605" + "reference": "bd8c740097eb9f2fc3735250fc1912bc811a954e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/86b5ca2f67173c9d34340845dd690149c886a605", - "reference": "86b5ca2f67173c9d34340845dd690149c886a605", + "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/bd8c740097eb9f2fc3735250fc1912bc811a954e", + "reference": "bd8c740097eb9f2fc3735250fc1912bc811a954e", "shasum": "" }, "require": { "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", "ext-zip": "*", "php": "^5.6 || ~7.0", "symfony/process": "^2.8 || ^3.1 || ^4.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.0", - "guzzle/guzzle": "^3.4.1", - "php-coveralls/php-coveralls": "^1.0.2", + "jakub-onderka/php-parallel-lint": "^0.9.2", + "php-coveralls/php-coveralls": "^2.0", "php-mock/php-mock-phpunit": "^1.1", "phpunit/phpunit": "^5.7", "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", "squizlabs/php_codesniffer": "^2.6", "symfony/var-dumper": "^3.3 || ^4.0" }, + "suggest": { + "ext-SimpleXML": "For Firefox profile creation" + }, "type": "library", "extra": { "branch-alias": { @@ -3275,7 +3681,7 @@ "selenium", "webdriver" ], - "time": "2017-11-15T11:08:09+00:00" + "time": "2018-05-16T17:37:13+00:00" }, { "name": "florianwolters/component-core-stringutils", @@ -3419,16 +3825,16 @@ }, { "name": "fzaninotto/faker", - "version": "v1.7.1", + "version": "v1.8.0", "source": { "type": "git", "url": "https://github.com/fzaninotto/Faker.git", - "reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d" + "reference": "f72816b43e74063c8b10357394b6bba8cb1c10de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/d3ed4cc37051c1ca52d22d76b437d14809fc7e0d", - "reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/f72816b43e74063c8b10357394b6bba8cb1c10de", + "reference": "f72816b43e74063c8b10357394b6bba8cb1c10de", "shasum": "" }, "require": { @@ -3436,7 +3842,7 @@ }, "require-dev": { "ext-intl": "*", - "phpunit/phpunit": "^4.0 || ^5.0", + "phpunit/phpunit": "^4.8.35 || ^5.7", "squizlabs/php_codesniffer": "^1.5" }, "type": "library", @@ -3456,7 +3862,7 @@ ], "authors": [ { - "name": "François Zaninotto" + "name": "François Zaninotto" } ], "description": "Faker is a PHP library that generates fake data for you.", @@ -3465,7 +3871,7 @@ "faker", "fixtures" ], - "time": "2017-08-15T16:48:10+00:00" + "time": "2018-07-12T10:23:15+00:00" }, { "name": "graphp/algorithms", @@ -3518,70 +3924,47 @@ "time": "2015-03-08T10:12:01+00:00" }, { - "name": "guzzle/guzzle", - "version": "v3.1.2", + "name": "guzzlehttp/guzzle", + "version": "6.3.3", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "7901ea7d27373d0cc85eac6f6694e4c2ced90a26" + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7901ea7d27373d0cc85eac6f6694e4c2ced90a26", - "reference": "7901ea7d27373d0cc85eac6f6694e4c2ced90a26", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", "shasum": "" }, "require": { - "ext-curl": "*", - "php": ">=5.3.2", - "symfony/event-dispatcher": ">=2.1" - }, - "replace": { - "guzzle/batch": "self.version", - "guzzle/cache": "self.version", - "guzzle/common": "self.version", - "guzzle/http": "self.version", - "guzzle/inflection": "self.version", - "guzzle/iterator": "self.version", - "guzzle/log": "self.version", - "guzzle/parser": "self.version", - "guzzle/plugin": "self.version", - "guzzle/plugin-async": "self.version", - "guzzle/plugin-backoff": "self.version", - "guzzle/plugin-cache": "self.version", - "guzzle/plugin-cookie": "self.version", - "guzzle/plugin-curlauth": "self.version", - "guzzle/plugin-history": "self.version", - "guzzle/plugin-log": "self.version", - "guzzle/plugin-md5": "self.version", - "guzzle/plugin-mock": "self.version", - "guzzle/plugin-oauth": "self.version", - "guzzle/service": "self.version", - "guzzle/stream": "self.version" + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" }, "require-dev": { - "doctrine/common": "*", - "monolog/monolog": "1.*", - "phpunit/phpunit": "3.7.*", - "symfony/class-loader": "*", - "zend/zend-cache1": "1.12", - "zend/zend-log1": "1.12", - "zendframework/zend-cache": "2.0.*", - "zendframework/zend-log": "2.0.*" + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "6.3-dev" } }, "autoload": { - "psr-0": { - "Guzzle\\Tests": "tests/", - "Guzzle": "src/" + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" } }, - "notification-url": "http://packagist.org/downloads/", + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -3590,13 +3973,9 @@ "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" - }, - { - "name": "Guzzle Community", - "homepage": "https://github.com/guzzle/guzzle/contributors" } ], - "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", + "description": "Guzzle is a PHP HTTP client library", "homepage": "http://guzzlephp.org/", "keywords": [ "client", @@ -3607,8 +3986,123 @@ "rest", "web service" ], - "abandoned": "guzzlehttp/guzzle", - "time": "2013-01-28T00:07:40+00:00" + "time": "2018-04-22T15:46:56+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-12-20T10:07:11+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2017-03-20T17:10:46+00:00" }, { "name": "instaclick/php-webdriver", @@ -3671,16 +4165,16 @@ }, { "name": "lmc/steward", - "version": "2.3.3", + "version": "2.3.4", "source": { "type": "git", "url": "https://github.com/lmc-eu/steward.git", - "reference": "f40db91e7378a373ada4505932d8ba2d8a4ea04a" + "reference": "a4738179a6f3ccee72fa20957c8546c4c53c9ab9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lmc-eu/steward/zipball/f40db91e7378a373ada4505932d8ba2d8a4ea04a", - "reference": "f40db91e7378a373ada4505932d8ba2d8a4ea04a", + "url": "https://api.github.com/repos/lmc-eu/steward/zipball/a4738179a6f3ccee72fa20957c8546c4c53c9ab9", + "reference": "a4738179a6f3ccee72fa20957c8546c4c53c9ab9", "shasum": "" }, "require": { @@ -3748,7 +4242,7 @@ "testing", "webdriver" ], - "time": "2018-03-12T00:56:44+00:00" + "time": "2018-07-26T22:03:36+00:00" }, { "name": "myclabs/deep-copy", @@ -3866,27 +4360,27 @@ }, { "name": "nette/finder", - "version": "v2.4.1", + "version": "v2.4.2", "source": { "type": "git", "url": "https://github.com/nette/finder.git", - "reference": "4d43a66d072c57d585bf08a3ef68d3587f7e9547" + "reference": "ee951a656cb8ac622e5dd33474a01fd2470505a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/finder/zipball/4d43a66d072c57d585bf08a3ef68d3587f7e9547", - "reference": "4d43a66d072c57d585bf08a3ef68d3587f7e9547", + "url": "https://api.github.com/repos/nette/finder/zipball/ee951a656cb8ac622e5dd33474a01fd2470505a0", + "reference": "ee951a656cb8ac622e5dd33474a01fd2470505a0", "shasum": "" }, "require": { - "nette/utils": "^2.4 || ~3.0.0", + "nette/utils": "~2.4", "php": ">=5.6.0" }, "conflict": { "nette/nette": "<2.2" }, "require-dev": { - "nette/tester": "^2.0", + "nette/tester": "~2.0", "tracy/tracy": "^2.3" }, "type": "library", @@ -3916,9 +4410,15 @@ "homepage": "https://nette.org/contributors" } ], - "description": "Nette Finder: Files Searching", + "description": "🔍 Nette Finder: find files and directories with an intuitive API.", "homepage": "https://nette.org", - "time": "2017-07-10T23:47:08+00:00" + "keywords": [ + "filesystem", + "glob", + "iterator", + "nette" + ], + "time": "2018-06-28T11:49:23+00:00" }, { "name": "nette/reflection", @@ -3986,16 +4486,16 @@ }, { "name": "nette/utils", - "version": "v2.5.2", + "version": "v2.5.3", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "183069866dc477fcfbac393ed486aaa6d93d19a5" + "reference": "17b9f76f2abd0c943adfb556e56f2165460b15ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/183069866dc477fcfbac393ed486aaa6d93d19a5", - "reference": "183069866dc477fcfbac393ed486aaa6d93d19a5", + "url": "https://api.github.com/repos/nette/utils/zipball/17b9f76f2abd0c943adfb556e56f2165460b15ce", + "reference": "17b9f76f2abd0c943adfb556e56f2165460b15ce", "shasum": "" }, "require": { @@ -4046,7 +4546,7 @@ "homepage": "https://nette.org/contributors" } ], - "description": "? Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", "homepage": "https://nette.org", "keywords": [ "array", @@ -4064,7 +4564,7 @@ "utility", "validation" ], - "time": "2018-05-02T17:16:08+00:00" + "time": "2018-09-18T10:22:16+00:00" }, { "name": "ondram/ci-detector", @@ -4267,16 +4767,16 @@ }, { "name": "phpspec/prophecy", - "version": "1.7.6", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", "shasum": "" }, "require": { @@ -4288,12 +4788,12 @@ }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.8.x-dev" } }, "autoload": { @@ -4326,7 +4826,7 @@ "spy", "stub" ], - "time": "2018-04-18T13:57:24+00:00" + "time": "2018-08-05T17:53:17+00:00" }, { "name": "phpunit/php-code-coverage", @@ -4716,8 +5216,59 @@ "mock", "xunit" ], + "abandoned": true, "time": "2017-06-30T09:13:00+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": "sebastian/code-unit-reverse-lookup", "version": "1.0.1", @@ -5233,16 +5784,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.2.3", + "version": "3.3.2", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "4842476c434e375f9d3182ff7b89059583aa8b27" + "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/4842476c434e375f9d3182ff7b89059583aa8b27", - "reference": "4842476c434e375f9d3182ff7b89059583aa8b27", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/6ad28354c04b364c3c71a34e4a18b629cc3b231e", + "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e", "shasum": "" }, "require": { @@ -5280,20 +5831,20 @@ "phpcs", "standards" ], - "time": "2018-02-20T21:35:23+00:00" + "time": "2018-09-23T23:08:17+00:00" }, { "name": "symfony/class-loader", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/class-loader.git", - "reference": "e63c12699822bb3b667e7216ba07fbcc3a3e203e" + "reference": "420458095cf60025eb0841276717e0da7f75e50e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/class-loader/zipball/e63c12699822bb3b667e7216ba07fbcc3a3e203e", - "reference": "e63c12699822bb3b667e7216ba07fbcc3a3e203e", + "url": "https://api.github.com/repos/symfony/class-loader/zipball/420458095cf60025eb0841276717e0da7f75e50e", + "reference": "420458095cf60025eb0841276717e0da7f75e50e", "shasum": "" }, "require": { @@ -5336,20 +5887,20 @@ ], "description": "Symfony ClassLoader Component", "homepage": "https://symfony.com", - "time": "2018-01-03T07:37:34+00:00" + "time": "2018-11-11T19:48:54+00:00" }, { "name": "symfony/options-resolver", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "f3109a6aedd20e35c3a33190e932c2b063b7b50e" + "reference": "2cf5aa084338c1f67166013aebe87e2026bbe953" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/f3109a6aedd20e35c3a33190e932c2b063b7b50e", - "reference": "f3109a6aedd20e35c3a33190e932c2b063b7b50e", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/2cf5aa084338c1f67166013aebe87e2026bbe953", + "reference": "2cf5aa084338c1f67166013aebe87e2026bbe953", "shasum": "" }, "require": { @@ -5390,20 +5941,20 @@ "configuration", "options" ], - "time": "2018-01-11T07:56:07+00:00" + "time": "2018-11-11T19:48:54+00:00" }, { "name": "symfony/stopwatch", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "eb17cfa072cab26537ac37e9c4ece6c0361369af" + "reference": "0f43969ab2718de55c1c1158dce046668079788d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/eb17cfa072cab26537ac37e9c4ece6c0361369af", - "reference": "eb17cfa072cab26537ac37e9c4ece6c0361369af", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/0f43969ab2718de55c1c1158dce046668079788d", + "reference": "0f43969ab2718de55c1c1158dce046668079788d", "shasum": "" }, "require": { @@ -5439,24 +5990,25 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2018-02-17T14:55:25+00:00" + "time": "2018-11-11T19:48:54+00:00" }, { "name": "symfony/yaml", - "version": "v3.4.9", + "version": "v3.4.19", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "033cfa61ef06ee0847e056e530201842b6e926c3" + "reference": "291e13d808bec481eab83f301f7bff3e699ef603" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/033cfa61ef06ee0847e056e530201842b6e926c3", - "reference": "033cfa61ef06ee0847e056e530201842b6e926c3", + "url": "https://api.github.com/repos/symfony/yaml/zipball/291e13d808bec481eab83f301f7bff3e699ef603", + "reference": "291e13d808bec481eab83f301f7bff3e699ef603", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { "symfony/console": "<3.4" @@ -5497,7 +6049,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2018-04-08T08:21:29+00:00" + "time": "2018-11-11T19:48:54+00:00" }, { "name": "webmozart/assert", @@ -5551,55 +6103,62 @@ }, { "name": "wimg/php-compatibility", - "version": "8.1.0", + "version": "9.0.0", "source": { "type": "git", - "url": "https://github.com/wimg/PHPCompatibility.git", - "reference": "4ac01e4fe8faaa4f8d3b3cd06ea92e5418ce472e" + "url": "https://github.com/PHPCompatibility/PHPCompatibility.git", + "reference": "e9f4047e5edf53c88f36f1dafc0d49454ce13e25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wimg/PHPCompatibility/zipball/4ac01e4fe8faaa4f8d3b3cd06ea92e5418ce472e", - "reference": "4ac01e4fe8faaa4f8d3b3cd06ea92e5418ce472e", + "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/e9f4047e5edf53c88f36f1dafc0d49454ce13e25", + "reference": "e9f4047e5edf53c88f36f1dafc0d49454ce13e25", "shasum": "" }, "require": { "php": ">=5.3", - "squizlabs/php_codesniffer": "^2.2 || ^3.0.2" + "squizlabs/php_codesniffer": "^2.3 || ^3.0.2" }, "conflict": { "squizlabs/php_codesniffer": "2.6.2" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0" + "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0" }, "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3" + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.", + "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." }, "type": "phpcodesniffer-standard", - "autoload": { - "psr-4": { - "PHPCompatibility\\": "PHPCompatibility/" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL-3.0" + "LGPL-3.0-or-later" ], "authors": [ + { + "name": "Contributors", + "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" + }, { "name": "Wim Godden", + "homepage": "https://github.com/wimg", + "role": "lead" + }, + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl", "role": "lead" } ], - "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP version compatibility.", + "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", "homepage": "http://techblog.wimgodden.be/tag/codesniffer/", "keywords": [ "compatibility", "phpcs", "standards" ], - "time": "2017-12-27T21:58:38+00:00" + "abandoned": "phpcompatibility/php-compatibility", + "time": "2018-10-07T17:38:02+00:00" } ], "aliases": [], diff --git a/config/app.php b/config/app.php index 18c615493..651ebfc6a 100644 --- a/config/app.php +++ b/config/app.php @@ -12,7 +12,7 @@ return [ 'log' => env('APP_LOG', 'single'), 'log_level' => env('APP_LOG_LEVEL', 'debug'), 'cache_lifetime' => env('APP_CACHE_LIFETIME', 60), - + 'timezone' => 'UTC', 'providers' => [ FilesystemServiceProvider::class, CacheServiceProvider::class, @@ -21,7 +21,7 @@ return [ Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, Illuminate\Queue\QueueServiceProvider::class, Illuminate\Translation\TranslationServiceProvider::class, - + Laravel\Tinker\TinkerServiceProvider::class, ], 'aliases' => [ diff --git a/config/customMimeTypes.php b/config/customMimeTypes.php index c78f3e0fa..e3ec006b8 100644 --- a/config/customMimeTypes.php +++ b/config/customMimeTypes.php @@ -1,36 +1,669 @@ 'text/plain', + '3dm' => 'x-world/x-3dmf', + '3dmf' => 'x-world/x-3dmf', + 'a' => 'application/octet-stream', + 'aab' => 'application/x-authorware-bin', + 'aam' => 'application/x-authorware-map', + 'aas' => 'application/x-authorware-seg', + 'abc' => 'text/vnd.abc', + 'acgi' => 'text/html', + 'acutc' => 'application/vnd.acucorp', + 'afl' => 'video/animaflex', + 'afm' => 'application/x-font-type1', + 'afp' => 'application/vnd.ibm.modcap', + 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'aim' => 'application/x-aim', + 'aip' => 'text/x-audiosoft-intra', + 'ani' => 'application/x-navi-animation', + 'aos' => 'application/x-nokia-9000-communicator-add-on-software', + 'aps' => 'application/mime', + 'arc' => 'application/octet-stream', + 'arj' => 'application/octet-stream', + 'art' => 'image/x-jg', + 'asf' => 'video/x-ms-asf', + 'asm' => 'text/x-asm', + 'asp' => 'text/asp', + 'asx' => 'video/x-ms-asf-plugin', + 'asx ' => 'video/x-ms-asf', + 'atc' => 'application/vnd.acucorp', + 'au' => ['audio/basic', 'audio/x-au'], + 'avi' => 'video/x-msvideo', + 'avs' => 'video/avs-video', + 'bat' => 'application/x-msdownload', + 'bcpio' => 'application/x-bcpio', + 'bin' => 'application/x-macbinary', + 'bm' => 'image/bmp', + 'bmp' => 'image/x-windows-bmp', + 'boo' => 'application/book', + 'book' => ['application/vnd.framemaker', 'application/book'], + 'boz' => 'application/x-bzip2', + 'bpk' => 'application/octet-stream', + 'bsh' => 'application/x-bsh', + 'bz' => 'application/x-bzip', + 'bz2' => 'application/x-bzip2', + 'c' => 'text/x-c', + 'c++' => 'text/plain', + 'c4d' => 'application/vnd.clonk.c4group', + 'c4f' => 'application/vnd.clonk.c4group', + 'c4g' => 'application/vnd.clonk.c4group', + 'c4p' => 'application/vnd.clonk.c4group', + 'c4u' => 'application/vnd.clonk.c4group', + 'cap' => 'application/vnd.tcpdump.pcap', + 'cat' => 'application/vnd.ms-pki.seccat', + 'cb7' => 'application/x-cbr', + 'cba' => 'application/x-cbr', + 'cbr' => 'application/x-cbr', + 'cbt' => 'application/x-cbr', + 'cbz' => 'application/x-cbr', + 'cc' => 'text/x-c', + 'ccad' => 'application/clariscad', + 'cco' => 'application/x-cocoa', + 'cct' => 'application/x-director', + 'cdf' => 'application/x-netcdf', + 'cer' => 'application/x-x509-ca-cert', + 'cha' => 'application/x-chat', + 'chat' => 'application/x-chat', + 'class' => 'application/x-java-class', + 'com' => ['application/x-msdownload', 'text/plain'], + 'conf' => 'text/plain', + 'cpio' => 'application/x-cpio', + 'cpp' => 'text/x-c', + 'cpt' => 'application/x-cpt', + 'crl' => 'application/pkix-crl', + 'crt' => 'application/x-x509-user-cert', + 'csh' => 'text/x-script.csh', + 'css' => 'text/css', + 'cst' => 'application/x-director', + 'cxt' => 'application/x-director', + 'cxx' => ['text/x-c', 'text/plain'], + 'dataless' => 'application/vnd.fdsn.seed', + 'dcr' => 'application/x-director', + 'deepv' => 'application/x-deepv', + 'def' => 'text/plain', + 'deploy' => 'application/octet-stream', + 'der' => 'application/x-x509-ca-cert', + 'dic' => 'text/x-c', + 'dif' => 'video/x-dv', + 'dir' => 'application/x-director', + 'dist' => 'application/octet-stream', + 'distz' => 'application/octet-stream', + 'djv' => 'image/vnd.djvu', + 'djvu' => 'image/vnd.djvu', + 'dl' => 'video/x-dl', + 'dll' => 'application/x-msdownload', + 'dmp' => 'application/vnd.tcpdump.pcap', + 'dms' => 'application/octet-stream', 'doc' => ['application/msword', 'text/html'], - 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'exe' => ['application/x-msdownload', 'application/x-dosexec'], + 'docx' => 'application/octet-stream', + 'dot' => 'application/msword', + 'dp' => 'application/commonground', + 'drw' => 'application/drafting', + 'dump' => 'application/octet-stream', + 'dv' => 'video/x-dv', + 'dvi' => 'application/x-dvi', + 'dwf' => 'model/vnd.dwf', + 'dwg' => 'image/x-dwg', + 'dxf' => 'image/x-dwg', + 'dxr' => 'application/x-director', + 'el' => 'text/x-script.elisp', + 'elc' => ['application/octet-stream', 'application/x-elc'], + 'emf' => 'application/x-msmetafile', + 'eml' => 'message/rfc822', + 'emz' => 'application/x-msmetafile', + 'env' => 'application/x-envoy', + 'eps' => 'application/postscript', + 'es' => 'application/x-esrehber', + 'es3' => 'application/vnd.eszigno3+xml', + 'et3' => 'application/vnd.eszigno3+xml', + 'etx' => 'text/x-setext', + 'evy' => 'application/x-envoy', + 'exe' => ['application/x-dosexec', 'application/octet-stream'], + 'f' => 'text/x-fortran', + 'f77' => 'text/x-fortran', + 'f90' => 'text/x-fortran', + 'fdf' => 'application/vnd.fdf', + 'fgd' => 'application/x-director', + 'fh' => 'image/x-freehand', + 'fh4' => 'image/x-freehand', + 'fh5' => 'image/x-freehand', + 'fh7' => 'image/x-freehand', + 'fhc' => 'image/x-freehand', + 'fif' => 'image/fif', + 'fli' => 'video/x-fli', + 'flo' => 'image/florian', + 'flx' => 'text/vnd.fmi.flexstor', + 'fm' => 'application/vnd.framemaker', + 'fmf' => 'video/x-atomic3d-feature', + 'for' => 'text/x-fortran', + 'fpx' => 'image/vnd.net-fpx', + 'frame' => 'application/vnd.framemaker', + 'frl' => 'application/freeloader', + 'funk' => 'audio/make', + 'fxp' => 'application/vnd.adobe.fxp', + 'fxpl' => 'application/vnd.adobe.fxp', + 'g' => 'text/plain', + 'g3' => 'image/g3fax', + 'gex' => 'application/vnd.geometry-explorer', 'gif' => 'image/gif', + 'gl' => 'video/x-gl', + 'gqf' => 'application/vnd.grafeq', + 'gqs' => 'application/vnd.grafeq', + 'gre' => 'application/vnd.geometry-explorer', + 'gsd' => 'audio/x-gsm', + 'gsm' => 'audio/x-gsm', + 'gsp' => 'application/x-gsp', + 'gss' => 'application/x-gss', + 'gtar' => 'application/x-gtar', + 'gz' => 'application/x-gzip', + 'gzip' => 'multipart/x-gzip', + 'h' => ['text/x-c', 'text/x-h'], + 'hdf' => 'application/x-hdf', + 'help' => 'application/x-helpfile', + 'hgl' => 'application/vnd.hp-hpgl', + 'hh' => ['text/x-c', 'text/x-h'], + 'hlb' => 'text/x-script', + 'hlp' => 'application/x-winhelp', + 'hpg' => 'application/vnd.hp-hpgl', + 'hpgl' => 'application/vnd.hp-hpgl', + 'hqx' => 'application/x-mac-binhex40', + 'hta' => 'application/hta', + 'htc' => 'text/x-component', 'htm' => 'text/html', 'html' => 'text/html', - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'mp3' => 'audio/mpeg', + 'htmls' => 'text/html', + 'htt' => 'text/webviewhtml', + 'htx' => 'text/html', + 'icc' => 'application/vnd.iccprofile', + 'ice' => 'x-conference/x-cooltalk', + 'icm' => 'application/vnd.iccprofile', + 'ico' => 'image/x-icon', + 'ics' => 'text/calendar', + 'idc' => 'text/plain', + 'ief' => 'image/ief', + 'iefs' => 'image/ief', + 'ifb' => 'text/calendar', + 'iges' => 'model/iges', + 'igs' => 'model/iges', + 'ima' => 'application/x-ima', + 'imap' => 'application/x-httpd-imap', + 'in' => 'text/plain', + 'inf' => 'application/inf', + 'inkml' => 'application/inkml+xml', + 'ins' => 'application/x-internett-signup', + 'ip' => 'application/x-ip2', + 'isu' => 'video/x-isvideo', + 'it' => 'audio/it', + 'iv' => 'application/x-inventor', + 'ivr' => 'i-world/i-vrml', + 'ivy' => 'application/x-livescreen', + 'jam' => 'audio/x-jam', + 'jav' => 'text/x-java-source', + 'java' => 'text/x-java-source', + 'jcm' => 'application/x-java-commerce', + 'jfif' => 'image/pjpeg', + 'jfif-tbnl' => 'image/jpeg', + 'jpe' => ['image/jpeg', 'image/pjpeg'], + 'jpeg' => ['image/jpeg', 'image/pjpeg'], + 'jpg' => ['image/pjpeg', 'image/jpeg'], + 'jpgm' => 'video/jpm', + 'jpm' => 'video/jpm', + 'jps' => 'image/x-jps', + 'js' => 'text/ecmascript', + 'json' => ['text/plain', 'text/json', 'text/javascript'], + 'jsonp' => 'application/javascript', + 'jut' => 'image/jutvision', + 'kar' => ['audio/midi', 'music/x-karaoke'], + 'kne' => 'application/vnd.kinar', + 'knp' => 'application/vnd.kinar', + 'kpr' => 'application/vnd.kde.kpresenter', + 'kpt' => 'application/vnd.kde.kpresenter', + 'ksh' => 'text/x-script.ksh', + 'ktr' => 'application/vnd.kahootz', + 'ktz' => 'application/vnd.kahootz', + 'kwd' => 'application/vnd.kde.kword', + 'kwt' => 'application/vnd.kde.kword', + 'la' => 'audio/x-nspaudio', + 'lam' => 'audio/x-liveaudio', + 'latex' => 'application/x-latex', + 'lha' => 'application/x-lha', + 'lhx' => 'application/octet-stream', + 'list' => 'text/plain', + 'list3820' => 'application/vnd.ibm.modcap', + 'listafp' => 'application/vnd.ibm.modcap', + 'lma' => 'audio/x-nspaudio', + 'log' => 'text/plain', + 'lrf' => 'application/octet-stream', + 'lsp' => 'text/x-script.lisp', + 'lst' => 'text/plain', + 'lsx' => 'text/x-la-asf', + 'ltx' => 'application/x-latex', + 'lzh' => 'application/x-lzh', + 'lzx' => 'application/x-lzx', + 'm' => 'text/x-m', + 'm13' => 'application/x-msmediaview', + 'm14' => 'application/x-msmediaview', + 'm1v' => 'video/mpeg', + 'm2a' => 'audio/mpeg', + 'm2v' => 'video/mpeg', + 'm3a' => 'audio/mpeg', + 'm3u' => 'audio/x-mpequrl', + 'm4a' => ['audio/mp4', 'audio/x-m4a'], + 'm4u' => 'video/vnd.mpegurl', + 'maker' => 'application/vnd.framemaker', + 'man' => ['text/troff', 'music/x-karaoke'], + 'map' => 'application/x-navimap', + 'mar' => ['application/octet-stream', 'text/plain'], + 'mb' => 'application/mathematica', + 'mbd' => 'application/mbedlet', + 'mc$' => 'application/x-magic-cap-package-1.0', + 'mcd' => 'application/x-mathcad', + 'mcf' => 'text/mcf', + 'mcp' => 'application/netmc', + 'me' => ['text/troff', 'application/x-troff-me'], + 'mesh' => 'model/mesh', + 'mht' => 'message/rfc822', + 'mhtml' => 'message/rfc822', + 'mid' => ['audio/midi', 'application/x-troff-me'], + 'midi' => ['audio/midi', 'application/x-troff-me'], + 'mif' => 'application/x-mif', + 'mime' => ['message/rfc822', 'www/mime'], + 'mj2' => 'video/mj2', + 'mjf' => 'audio/x-vnd.audioexplosion.mjuicemediafile', + 'mjp2' => 'video/mj2', + 'mjpg' => 'video/x-motion-jpeg', + 'mk3d' => 'video/x-matroska', + 'mks' => 'video/x-matroska', + 'mkv' => 'video/x-matroska', + 'mm' => 'application/x-meme', + 'mme' => 'application/base64', + 'mod' => 'audio/x-mod', + 'moov' => 'video/quicktime', + 'mov' => 'video/quicktime', + 'movie' => 'video/x-sgi-movie', + 'mp2' => ['audio/mpeg', 'video/x-mpeq2a'], + 'mp2a' => 'audio/mpeg', + 'mp3' => ['video/x-mpeg', 'audio/mpeg'], 'mp4' => 'video/mp4', - 'ppt' => 'application/vnd.ms-office', - 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'pm' => 'text/plain', - 'pmt' => 'text/plain', - 'pmx' => 'application/xml', - 'po' => 'text/x-po', + 'mp4a' => 'audio/mp4', + 'mp4v' => 'video/mp4', + 'mpa' => 'video/mpeg', + 'mpc' => 'application/x-project', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpg4' => 'video/mp4', + 'mpga' => 'audio/mpeg', + 'mpp' => 'application/vnd.ms-project', + 'mpt' => ['application/vnd.ms-project', 'application/x-project'], + 'mpv' => 'application/x-project', + 'mpx' => 'application/x-project', + 'mrc' => 'application/marc', + 'ms' => ['text/troff', 'application/x-troff-ms'], + 'msh' => 'model/mesh', + 'msi' => 'application/x-msdownload', + 'mv' => 'video/x-sgi-movie', + 'mvb' => 'application/x-msmediaview', + 'mxml' => 'application/xv+xml', + 'mxu' => 'video/vnd.mpegurl', + 'my' => 'audio/make', + 'mzz' => 'application/x-vnd.audioexplosion.mzz', + 'nap' => 'image/naplps', + 'naplps' => 'image/naplps', + 'nb' => 'application/mathematica', + 'nc' => 'application/x-netcdf', + 'ncm' => 'application/vnd.nokia.Something is wronguration-message', + 'nif' => 'image/x-niff', + 'niff' => 'image/x-niff', + 'nitf' => 'application/vnd.nitf', + 'nix' => 'application/x-mix-transfer', + 'nsc' => 'application/x-conference', + 'ntf' => 'application/vnd.nitf', + 'nvd' => 'application/x-navidoc', + 'o' => 'application/octet-stream', + 'oda' => 'application/oda', + 'oga' => 'audio/ogg', + 'ogg' => 'audio/ogg', + 'omc' => 'application/x-omc', + 'omcd' => 'application/x-omcdatamaker', + 'omcr' => 'application/x-omcregerator', + 'onepkg' => 'application/onenote', + 'onetmp' => 'application/onenote', + 'onetoc2' => 'application/onenote', + 'oprc' => 'application/vnd.palm', + 'p' => 'text/x-pascal', + 'p10' => 'application/x-pkcs10', + 'p12' => 'application/x-pkcs12', + 'p7a' => 'application/x-pkcs7-signature', + 'p7b' => 'application/x-pkcs7-certificates', + 'p7c' => ['application/pkcs7-mime', 'application/x-pkcs7-mime'], + 'p7m' => 'application/x-pkcs7-mime', + 'p7r' => 'application/x-pkcs7-certreqresp', + 'p7s' => 'application/pkcs7-signature', + 'part' => 'application/pro_eng', + 'pas' => 'text/pascal', + 'pbm' => 'image/x-portable-bitmap', + 'pcap' => 'application/vnd.tcpdump.pcap', + 'pcl' => 'application/x-pcl', + 'pct' => 'image/x-pict', + 'pcx' => 'image/x-pcx', + 'pdb' => ['application/vnd.palm', 'chemical/x-pdb'], 'pdf' => 'application/pdf', - 'png' => 'image/png', + 'pfa' => 'application/x-font-type1', + 'pfb' => 'application/x-font-type1', + 'pfm' => 'application/x-font-type1', + 'pfunk' => 'audio/make.my.funk', + 'pfx' => 'application/x-pkcs12', + 'pgm' => 'image/x-portable-greymap', 'php' => 'text/x-php', - 'rar' => 'application/x-rar', + 'pic' => ['image/x-pict', 'image/pict'], + 'pict' => 'image/pict', + 'pkg' => ['application/octet-stream', 'application/x-newton-compatible-pkg'], + 'pko' => 'application/vnd.ms-pki.pko', + 'pl' => 'text/x-script.perl', + 'plx' => 'application/x-pixclscript', + 'pm' => 'text/x-script.perl-module', + 'pm4' => 'application/x-pagemaker', + 'pm5' => 'application/x-pagemaker', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'pot' => 'application/vnd.ms-powerpoint', + 'pov' => 'model/x-pov', + 'ppa' => 'application/vnd.ms-powerpoint', + 'ppm' => 'image/x-portable-pixmap', + 'pps' => 'application/vnd.ms-powerpoint', + 'ppt' => ['application/x-mspowerpoint', 'application/vnd.ms-office'], + 'ppz' => 'application/mspowerpoint', + 'pqa' => 'application/vnd.palm', + 'pre' => 'application/x-freelance', + 'prt' => 'application/pro_eng', + 'ps' => 'application/postscript', + 'psd' => 'application/octet-stream', + 'pvu' => 'paleovu/x-pv', + 'pwz' => 'application/vnd.ms-powerpoint', + 'py' => 'text/x-script.phyton', + 'pyc' => 'application/x-bytecode.python', + 'qcp' => 'audio/vnd.qcelp', + 'qd3' => 'x-world/x-3dmf', + 'qd3d' => 'x-world/x-3dmf', + 'qif' => 'image/x-quicktime', + 'qt' => 'video/quicktime', + 'qtc' => 'video/x-qtc', + 'qti' => 'image/x-quicktime', + 'qtif' => 'image/x-quicktime', + 'qwd' => 'application/vnd.quark.quarkxpress', + 'qwt' => 'application/vnd.quark.quarkxpress', + 'qxb' => 'application/vnd.quark.quarkxpress', + 'qxd' => 'application/vnd.quark.quarkxpress', + 'qxl' => 'application/vnd.quark.quarkxpress', + 'qxt' => 'application/vnd.quark.quarkxpress', + 'ra' => ['audio/x-pn-realaudio', 'audio/x-realaudio'], + 'ram' => 'audio/x-pn-realaudio', + 'ras' => 'image/x-cmu-raster', + 'rast' => 'image/cmu-raster', + 'rexx' => 'text/x-script.rexx', + 'rf' => 'image/vnd.rn-realflash', + 'rgb' => 'image/x-rgb', + 'rm' => 'audio/x-pn-realaudio', + 'rmi' => ['audio/midi', 'audio/mid'], + 'rmm' => 'audio/x-pn-realaudio', + 'rmp' => 'audio/x-pn-realaudio-plugin', + 'rng' => 'application/vnd.nokia.ringing-tone', + 'rnx' => 'application/vnd.rn-realplayer', + 'roff' => ['text/troff', 'application/x-troff'], + 'rp' => 'image/vnd.rn-realpix', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'rt' => 'text/vnd.rn-realtext', + 'rtf' => 'text/richtext', + 'rtx' => 'text/richtext', + 'rv' => 'video/vnd.rn-realvideo', + 's' => 'text/x-asm', + 's3m' => 'audio/s3m', + 'saveme' => 'application/octet-stream', + 'sbk' => 'application/x-tbook', + 'scm' => 'video/x-scm', + 'sdkd' => 'application/vnd.solent.sdkm+xml', + 'sdkm' => 'application/vnd.solent.sdkm+xml', + 'sdml' => 'text/plain', + 'sdp' => 'application/x-sdp', + 'sdr' => 'application/sounder', + 'sdw' => 'application/vnd.stardivision.writer', + 'sea' => 'application/x-sea', + 'seed' => 'application/vnd.fdsn.seed', + 'set' => 'application/set', + 'sgm' => ['text/sgml', 'text/x-sgml'], + 'sgml' => ['text/sgml', 'text/x-sgml'], + 'sh' => 'text/x-script.sh', + 'shar' => 'application/x-shar', + 'shtml' => 'text/x-server-parsed-html', + 'sid' => 'audio/x-psid', + 'sig' => 'application/pgp-signature', + 'silo' => 'model/mesh', + 'sis' => 'application/vnd.symbian.install', + 'sisx' => 'application/vnd.symbian.install', + 'sit' => 'application/x-stuffit', + 'skd' => ['application/vnd.koan', 'application/x-koan'], + 'skm' => ['application/vnd.koan', 'application/x-koan'], + 'skp' => ['application/vnd.koan', 'application/x-koan'], + 'skt' => ['application/vnd.koan', 'application/x-koan'], + 'sl' => 'application/x-seelogo', + 'smi' => ['application/smil+xml', 'application/smil'], + 'smil' => ['application/smil+xml', 'application/smil'], + 'snd' => 'audio/basic', + 'so' => 'application/octet-stream', + 'sol' => 'application/solids', + 'spc' => ['application/x-pkcs7-certificates', 'text/x-speech'], + 'spl' => 'application/futuresplash', + 'spr' => 'application/x-sprite', + 'sprite' => 'application/x-sprite', + 'spx' => 'audio/ogg', + 'src' => 'application/x-wais-source', + 'ssi' => 'text/x-server-parsed-html', + 'ssm' => 'application/streamingmedia', + 'sst' => 'application/vnd.ms-pki.certstore', + 'step' => 'application/step', + 'stl' => 'application/x-navistyle', + 'stp' => 'application/step', + 'sus' => 'application/vnd.sus-calendar', + 'susp' => 'application/vnd.sus-calendar', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', + 'svf' => 'image/x-dwg', + 'svr' => 'x-world/x-svr', + 'swa' => 'application/x-director', + 'swf' => 'application/x-shockwave-flash', + 't' => ['text/troff', 'application/x-troff'], + 'talk' => 'text/x-speech', + 'tar' => 'application/x-tar', + 'tbk' => 'application/x-tbook', + 'tcl' => 'text/x-script.tcl', + 'tcsh' => 'text/x-script.tcsh', + 'tei' => 'application/tei+xml', + 'teicorpus' => 'application/tei+xml', + 'tex' => 'application/x-tex', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', + 'text' => 'text/plain', + 'tgz' => 'application/x-compressed', + 'tif' => ['image/tiff', 'image/x-tiff'], + 'tiff' => ['image/tiff', 'image/x-tiff'], + 'tr' => ['text/troff', 'application/x-troff'], + 'tsi' => 'audio/tsp-audio', + 'tsp' => 'audio/tsplayer', + 'tsv' => 'text/tab-separated-values', + 'turbot' => 'image/florian', + 'twd' => 'application/vnd.simtech-mindmapper', + 'twds' => 'application/vnd.simtech-mindmapper', 'txt' => 'text/plain', + 'u32' => 'application/x-authorware-bin', + 'ufd' => 'application/vnd.ufdl', + 'ufdl' => 'application/vnd.ufdl', + 'uil' => 'text/x-uil', + 'uni' => 'text/uri-list', + 'unis' => 'text/uri-list', + 'unv' => 'application/i-deas', + 'uri' => 'text/uri-list', + 'uris' => 'text/uri-list', + 'urls' => 'text/uri-list', + 'ustar' => 'multipart/x-ustar', + 'uu' => 'text/x-uuencode', + 'uue' => 'text/x-uuencode', + 'uva' => 'audio/vnd.dece.audio', + 'uvd' => 'application/vnd.dece.data', + 'uvf' => 'application/vnd.dece.data', + 'uvg' => 'image/vnd.dece.graphic', + 'uvh' => 'video/vnd.dece.hd', + 'uvi' => 'image/vnd.dece.graphic', + 'uvm' => 'video/vnd.dece.mobile', + 'uvp' => 'video/vnd.dece.pd', + 'uvs' => 'video/vnd.dece.sd', + 'uvt' => 'application/vnd.dece.ttml+xml', + 'uvu' => 'video/vnd.uvvu.mp4', + 'uvv' => 'video/vnd.dece.video', + 'uvva' => 'audio/vnd.dece.audio', + 'uvvd' => 'application/vnd.dece.data', + 'uvvf' => 'application/vnd.dece.data', + 'uvvg' => 'image/vnd.dece.graphic', + 'uvvh' => 'video/vnd.dece.hd', + 'uvvi' => 'image/vnd.dece.graphic', + 'uvvm' => 'video/vnd.dece.mobile', + 'uvvp' => 'video/vnd.dece.pd', + 'uvvs' => 'video/vnd.dece.sd', + 'uvvt' => 'application/vnd.dece.ttml+xml', + 'uvvu' => 'video/vnd.uvvu.mp4', + 'uvvv' => 'video/vnd.dece.video', + 'uvvx' => 'application/vnd.dece.unspecified', + 'uvvz' => 'application/vnd.dece.zip', + 'uvx' => 'application/vnd.dece.unspecified', + 'uvz' => 'application/vnd.dece.zip', + 'vcd' => 'application/x-cdlink', + 'vcs' => 'text/x-vcalendar', + 'vda' => 'application/vda', + 'vdo' => 'video/vdo', + 'vew' => 'application/groupwise', + 'viv' => 'video/vnd.vivo', + 'vivo' => 'video/vnd.vivo', + 'vmd' => 'application/vocaltec-media-desc', + 'vmf' => 'application/vocaltec-media-file', + 'voc' => 'audio/x-voc', + 'vor' => 'application/vnd.stardivision.writer', + 'vos' => 'video/vosaic', + 'vox' => ['application/x-authorware-bin', 'audio/voxware'], + 'vqe' => 'audio/x-twinvq-plugin', + 'vqf' => 'audio/x-twinvqv', + 'vql' => 'audio/x-twinvq-plugin', + 'vrml' => ['model/vrml', 'x-world/x-vrml'], + 'vrt' => 'x-world/x-vrt', + 'vsd' => ['application/vnd.visio', 'application/x-visio'], + 'vss' => ['application/vnd.visio', 'application/x-visio'], + 'vst' => ['application/vnd.visio', 'application/x-visio'], + 'vsw' => ['application/vnd.visio', 'application/x-visio'], + 'w3d' => 'application/x-director', + 'w60' => 'application/wordperfect6.0', + 'w61' => 'application/wordperfect6.1', + 'w6w' => 'application/msword', + 'wav' => 'audio/x-wav', + 'wb1' => 'application/x-qpro', + 'wbmp' => 'image/vnd.wap.wbmp', + 'wcm' => 'application/vnd.ms-works', + 'wdb' => 'application/vnd.ms-works', + 'web' => 'application/vnd.xara', + 'wiz' => 'application/msword', + 'wk1' => 'application/x-123', + 'wks' => 'application/vnd.ms-works', + 'wmf' => ['application/x-msmetafile', 'windows/metafile'], + 'wml' => 'text/vnd.wap.wml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmls' => 'text/vnd.wap.wmlscript', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', 'wmv' => ['video/x-ms-asf', 'video/x-ms-wmv'], - 'xls' => ['application/vnd.ms-excel', 'text/plain'], - 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'zip' => 'application/zip', + 'wmz' => 'application/x-msmetafile', + 'word' => 'application/msword', + 'wp' => 'application/wordperfect', + 'wp5' => 'application/wordperfect6.0', + 'wp6' => 'application/wordperfect', + 'wpd' => 'application/x-wpwin', + 'wps' => 'application/vnd.ms-works', + 'wq1' => 'application/x-lotus', + 'wri' => 'application/x-wri', + 'wrl' => ['model/vrml', 'x-world/x-vrml'], + 'wrz' => 'x-world/x-vrml', + 'wsc' => 'text/scriplet', + 'wsrc' => 'application/x-wais-source', + 'wtk' => 'application/x-wintalk', + 'x-png' => 'image/png', + 'x32' => 'application/x-authorware-bin', + 'x3d' => 'model/x3d+xml', + 'x3db' => 'model/x3d+binary', + 'x3dbz' => 'model/x3d+binary', + 'x3dv' => 'model/x3d+vrml', + 'x3dvz' => 'model/x3d+vrml', + 'x3dz' => 'model/x3d+xml', + 'xbm' => 'image/xbm', + 'xdr' => 'video/x-amt-demorun', + 'xgz' => 'xgl/drawing', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xhvml' => 'application/xv+xml', + 'xif' => 'image/vnd.xiff', + 'xl' => 'application/excel', + 'xla' => ['application/vnd.ms-excel', 'application/x-msexcel'], + 'xlb' => 'application/x-excel', + 'xlc' => ['application/vnd.ms-excel', 'application/x-excel'], + 'xld' => 'application/x-excel', + 'xlk' => 'application/x-excel', + 'xll' => 'application/x-excel', + 'xlm' => ['application/vnd.ms-excel', 'application/x-excel'], + 'xls' => ['application/x-msexcel', 'text/plain'], + 'xlsx' => 'application/octet-stream', + 'xlt' => ['application/vnd.ms-excel', 'application/x-excel'], + 'xlv' => 'application/x-excel', + 'xlw' => ['application/vnd.ms-excel', 'application/x-msexcel'], + 'xm' => 'audio/xm', + 'xml' => ['application/xml', 'text/xml'], + 'xmz' => 'xgl/movie', + 'xpix' => 'application/x-vnd.ls-xpix', + 'xpm' => 'image/xpm', + 'x-png' => 'image/png', + 'xpw' => 'application/vnd.intercon.formnet', + 'xpx' => 'application/vnd.intercon.formnet', + 'xsl' => 'application/xml', + 'xsr' => 'video/x-amt-showrun', + 'xvm' => 'application/xv+xml', + 'xvml' => 'application/xv+xml', + 'xwd' => 'image/x-xwindowdump', + 'xyz' => 'chemical/x-pdb', + 'z' => 'application/x-compressed', + 'z1' => 'application/x-zmachine', + 'z2' => 'application/x-zmachine', + 'z3' => 'application/x-zmachine', + 'z4' => 'application/x-zmachine', + 'z5' => 'application/x-zmachine', + 'z6' => 'application/x-zmachine', + 'z7' => 'application/x-zmachine', + 'z8' => 'application/x-zmachine', + 'zip' => 'multipart/x-zip', + 'zir' => 'application/vnd.zul', + 'zirz' => 'application/vnd.zul', + 'zoo' => 'application/octet-stream', + 'zsh' => 'text/x-script.zsh', + //The following are the custom application mime type + 'dat' => 'text/plain', + 'pm' => ['text/plain', 'application/octet-stream'], + 'pmp' => ['application/xml', 'text/xml', 'text/html'], + 'pmt' => 'text/plain', + 'pmx' => ['application/xml', 'text/xml', 'text/html'], + 'pmx2' => ['application/xml', 'text/xml', 'text/html'], + 'po' => 'text/x-po', ]; diff --git a/database/factories/AppAssignSelfServiceValueFactory.php b/database/factories/AppAssignSelfServiceValueFactory.php new file mode 100644 index 000000000..f1b7360c1 --- /dev/null +++ b/database/factories/AppAssignSelfServiceValueFactory.php @@ -0,0 +1,18 @@ +define(\ProcessMaker\Model\AppAssignSelfServiceValue::class, function(Faker $faker) { + return [ + 'ID' => $faker->unique()->numberBetween(1, 2000), + 'APP_UID' => G::generateUniqueID(), + 'DEL_INDEX' => 2, + 'PRO_UID' => G::generateUniqueID(), + 'TAS_UID' => G::generateUniqueID(), + 'TAS_ID' => $faker->unique()->numberBetween(1, 2000), + 'GRP_UID' => G::generateUniqueID(), + ]; +}); + diff --git a/database/factories/AppAssignSelfServiceValueGroupFactory.php b/database/factories/AppAssignSelfServiceValueGroupFactory.php new file mode 100644 index 000000000..72057cb5c --- /dev/null +++ b/database/factories/AppAssignSelfServiceValueGroupFactory.php @@ -0,0 +1,15 @@ +define(\ProcessMaker\Model\AppAssignSelfServiceValueGroup::class, function(Faker $faker) { + return [ + 'ID' => $faker->unique()->numberBetween(1, 2000), + 'GRP_UID' => G::generateUniqueID(), + 'ASSIGNEE_ID' => $faker->unique()->numberBetween(1, 2000), + 'ASSIGNEE_TYPE' => $faker->unique()->numberBetween(1, 2000), + ]; +}); + diff --git a/database/factories/ApplicationFactory.php b/database/factories/ApplicationFactory.php new file mode 100644 index 000000000..76728224a --- /dev/null +++ b/database/factories/ApplicationFactory.php @@ -0,0 +1,26 @@ +define(\ProcessMaker\Model\Application::class, function(Faker $faker) { + $process = \ProcessMaker\Model\Process::all()->random(); + $statuses = ['DRAFT', 'TO_DO']; + $status = $faker->randomElement($statuses); + $statusId = array_search($status, $statuses) + 1; + return [ + 'APP_UID' => G::generateUniqueID(), + 'APP_TITLE' => G::generateUniqueID(), + 'APP_NUMBER' => $faker->unique()->numberBetween(1000), + 'APP_STATUS' => $status, + 'APP_STATUS_ID' => $statusId, + 'PRO_UID' => $process->PRO_UID, + 'APP_PARALLEL' => 'N', + 'APP_INIT_USER' => \ProcessMaker\Model\User::all()->random()->USR_UID, + 'APP_CUR_USER' => \ProcessMaker\Model\User::all()->random()->USR_UID, + 'APP_PIN' => G::generateUniqueID(), + 'APP_CREATE_DATE' => $faker->dateTime(), + 'APP_UPDATE_DATE' => $faker->dateTime(), + 'APP_INIT_DATE' => $faker->dateTime(), + 'APP_DATA' => serialize(['APP_NUMBER' => 12]) + ]; +}); \ No newline at end of file diff --git a/database/factories/DelegationFactory.php b/database/factories/DelegationFactory.php new file mode 100644 index 000000000..e5917a414 --- /dev/null +++ b/database/factories/DelegationFactory.php @@ -0,0 +1,38 @@ +define(\ProcessMaker\Model\Delegation::class, function(Faker $faker) { + $app = factory(\ProcessMaker\Model\Application::class)->create(); + $process = \ProcessMaker\Model\Process::where('PRO_UID', $app->PRO_UID)->first(); + $task = $process->tasks->first(); + + // Grab a user if random + $users = \ProcessMaker\Model\User::all(); + if(!count($users)) { + $user = factory(\ProcessMaker\Model\User::class)->create(); + } else{ + $user = $users->random(); + } + return [ + 'APP_UID' => $app->APP_UID, + 'DEL_INDEX' => 1, + 'APP_NUMBER' => $app->APP_NUMBER, + 'DEL_PREVIOUS' => 0, + 'PRO_UID' => $app->PRO_UID, + 'TAS_UID' => $task->TAS_UID, + 'USR_UID' => $user->USR_UID, + 'DEL_TYPE' => 'NORMAL', + 'DEL_THREAD' => 1, + 'DEL_THREAD_STATUS' => 'OPEN', + 'DEL_PRIORITY' => 3, + 'DEL_DELEGATE_DATE' => $faker->dateTime(), + 'DEL_INIT_DATE' => $faker->dateTime(), + 'DEL_TASK_DUE_DATE' => $faker->dateTime(), + 'DEL_RISK_DATE' => $faker->dateTime(), + 'USR_ID' => $user->USR_ID, + 'PRO_ID' => $process->PRO_ID, + 'TAS_ID' => $task->TAS_ID, + 'DEL_DATA' => '' + ]; +}); \ No newline at end of file diff --git a/database/factories/DynaformFactory.php b/database/factories/DynaformFactory.php new file mode 100644 index 000000000..c790e5fda --- /dev/null +++ b/database/factories/DynaformFactory.php @@ -0,0 +1,26 @@ +define(\ProcessMaker\Model\Dynaform::class, function(Faker $faker) { + $date = $faker->dateTime(); + return [ + 'DYN_UID' => G::generateUniqueID(), + 'DYN_ID' => '', + 'DYN_TITLE' => '', + 'DYN_DESCRIPTION' => '', + 'PRO_UID' => function() { + $process = factory(\ProcessMaker\Model\Process::class)->create(); + return $process->PRO_UID; + }, + 'DYN_TYPE' => 'xmlform', + 'DYN_FILENAME' => '', + 'DYN_CONTENT' => '', + 'DYN_LABEL' => '', + 'DYN_VERSION' => 2, + 'DYN_UPDATE_DATE' => $date->format('Y-m-d H:i:s'), + ]; +}); diff --git a/database/factories/GroupUserFactory.php b/database/factories/GroupUserFactory.php new file mode 100644 index 000000000..d7f51ee31 --- /dev/null +++ b/database/factories/GroupUserFactory.php @@ -0,0 +1,14 @@ +define(\ProcessMaker\Model\GroupUser::class, function(Faker $faker) { + return [ + 'GRP_UID' => G::generateUniqueID(), + 'GRP_ID' => $faker->unique()->numberBetween(1, 2000), + 'USR_UID' => G::generateUniqueID() + ]; +}); + diff --git a/database/factories/GroupwfFactory.php b/database/factories/GroupwfFactory.php new file mode 100644 index 000000000..7ab6ca271 --- /dev/null +++ b/database/factories/GroupwfFactory.php @@ -0,0 +1,17 @@ +define(\ProcessMaker\Model\Groupwf::class, function(Faker $faker) { + return [ + 'GRP_UID' => G::generateUniqueID(), + 'GRP_ID' => $faker->unique()->numberBetween(1, 2000), + 'GRP_TITLE' => $faker->sentence(2), + 'GRP_STATUS' => 'ACTIVE', + 'GRP_LDAP_DN' => '', + 'GRP_UX' => 'NORMAL', + ]; +}); + diff --git a/database/factories/ListUnassignedFactory.php b/database/factories/ListUnassignedFactory.php new file mode 100644 index 000000000..afbc01949 --- /dev/null +++ b/database/factories/ListUnassignedFactory.php @@ -0,0 +1,40 @@ +define(\ProcessMaker\Model\ListUnassigned::class, function (Faker $faker) { + $app = factory(\ProcessMaker\Model\Application::class)->create(); + $process = \ProcessMaker\Model\Process::where('PRO_UID', $app->PRO_UID)->first(); + $task = $process->tasks->first(); + // Grab a user if random + $users = \ProcessMaker\Model\User::all(); + if(!count($users)) { + $user = factory(\ProcessMaker\Model\User::class)->create(); + } else{ + $user = $users->random(); + } + + return [ + 'APP_UID' => $app->APP_UID, + 'DEL_INDEX' => 1, + 'TAS_UID' => $task->TAS_UID, + 'PRO_UID' => $app->PRO_UID, + 'APP_NUMBER' => $app->APP_NUMBER, + 'APP_TITLE' => $app->APP_TITLE, + 'APP_PRO_TITLE' => $process->PRO_TITLE, + 'APP_TAS_TITLE' => $task->TAS_TITLE, + 'DEL_PREVIOUS_USR_USERNAME' => $user->USR_USERNAME, + 'DEL_PREVIOUS_USR_FIRSTNAME' => $user->USR_FIRSTNAME, + 'DEL_PREVIOUS_USR_LASTNAME' => $user->USR_LASTNAME, + 'APP_UPDATE_DATE' => $faker->dateTime(), + 'DEL_PREVIOUS_USR_UID' => G::generateUniqueID(), + 'DEL_DELEGATE_DATE' => $faker->dateTime(), + 'DEL_DUE_DATE' => $faker->dateTime(), + 'DEL_PRIORITY' => 3, + 'PRO_ID' => $process->PRO_ID, + 'TAS_ID' => $task->TAS_ID, + ]; +}); + diff --git a/database/factories/ProcessCategoryFactory.php b/database/factories/ProcessCategoryFactory.php new file mode 100644 index 000000000..0f8f19776 --- /dev/null +++ b/database/factories/ProcessCategoryFactory.php @@ -0,0 +1,14 @@ +define(\ProcessMaker\Model\ProcessCategory::class, function (Faker $faker) { + return [ + 'CATEGORY_UID' => G::generateUniqueID(), + 'CATEGORY_PARENT' => '', + 'CATEGORY_NAME' => $faker->sentence(5), + 'CATEGORY_ICON' => '', + ]; +}); diff --git a/database/factories/ProcessFactory.php b/database/factories/ProcessFactory.php index d8a60d371..3bfa727ed 100644 --- a/database/factories/ProcessFactory.php +++ b/database/factories/ProcessFactory.php @@ -5,13 +5,57 @@ use Faker\Generator as Faker; $factory->define(\ProcessMaker\Model\Process::class, function(Faker $faker) { - /** * @todo Determine if we need more base columns populated */ - return [ + $process = [ 'PRO_UID' => G::generateUniqueID(), 'PRO_TITLE' => $faker->sentence(3), - 'PRO_DESCRIPTION' => $faker->paragraph(3) + 'PRO_DESCRIPTION' => $faker->paragraph(3), + 'PRO_CREATE_USER' => '00000000000000000000000000000001', + 'PRO_DYNAFORMS' => '', + 'PRO_ITEE' => 1, + 'PRO_STATUS' => 'ACTIVE' ]; + + $task1 = factory(\ProcessMaker\Model\Task::class) + ->create([ + 'PRO_UID' => $process['PRO_UID'], + 'TAS_START'=>'TRUE' + ]); + + $task2 = factory(\ProcessMaker\Model\Task::class) + ->create([ + 'PRO_UID' => $process['PRO_UID'], + ]); + + //routes + factory(\ProcessMaker\Model\Route::class) + ->create([ + 'PRO_UID' => $process['PRO_UID'], + 'TAS_UID' => $task2['TAS_UID'], + 'ROU_NEXT_TASK' => '-1', + ]); + + factory(\ProcessMaker\Model\Route::class) + ->create([ + 'PRO_UID' => $process['PRO_UID'], + 'TAS_UID' => $task1['TAS_UID'], + 'ROU_NEXT_TASK' => $task2['TAS_UID'] + ]); + + //User assignments + factory(\ProcessMaker\Model\TaskUser::class) + ->create([ + 'TAS_UID' => $task1['TAS_UID'], + 'USR_UID' => \ProcessMaker\Model\User::all()->random()->USR_UID + ]); + + factory(\ProcessMaker\Model\TaskUser::class) + ->create([ + 'TAS_UID' => $task2['TAS_UID'], + 'USR_UID' => \ProcessMaker\Model\User::all()->random()->USR_UID + ]); + + return $process; }); \ No newline at end of file diff --git a/database/factories/RouteFactory.php b/database/factories/RouteFactory.php new file mode 100644 index 000000000..18a3e2f57 --- /dev/null +++ b/database/factories/RouteFactory.php @@ -0,0 +1,22 @@ +define(\ProcessMaker\Model\Route::class, function(Faker $faker) { + return [ + 'PRO_UID' => function() { + $process = factory(\ProcessMaker\Model\Process::class)->create(); + return $process->PRO_UID; + }, + 'TAS_UID' => function() { + $task = factory(\ProcessMaker\Model\Task::class)->create(); + return $task->TAS_UID; + }, + 'ROU_UID' => G::generateUniqueID(), + 'ROU_PARENT' => 0, + 'ROU_CASE' => 1, + 'ROU_TYPE' => 'SEQUENTIAL' + ]; +}); \ No newline at end of file diff --git a/database/factories/TaskFactory.php b/database/factories/TaskFactory.php new file mode 100644 index 000000000..992afea7c --- /dev/null +++ b/database/factories/TaskFactory.php @@ -0,0 +1,34 @@ +define(\ProcessMaker\Model\Task::class, function(Faker $faker) { + return [ + 'PRO_UID' => function() { + $process = factory(\ProcessMaker\Model\Process::class)->create(); + return $process->PRO_UID; + }, + 'TAS_UID' => G::generateUniqueID(), + 'TAS_ID' => $faker->unique()->numberBetween(1, 2000), + 'TAS_TITLE' => $faker->sentence(2), + 'TAS_TYPE' => 'NORMAL', + 'TAS_TYPE_DAY' => 1, + 'TAS_DURATION' => 1, + 'TAS_ASSIGN_TYPE' => 'BALANCED', + 'TAS_ASSIGN_VARIABLE' => '@@SYS_NEXT_USER_TO_BE_ASSIGNED', + 'TAS_MI_INSTANCE_VARIABLE' => '@@SYS_VAR_TOTAL_INSTANCE', + 'TAS_MI_COMPLETE_VARIABLE' => '@@SYS_VAR_TOTAL_INSTANCES_COMPLETE', + 'TAS_ASSIGN_LOCATION' => 'FALSE', + 'TAS_ASSIGN_LOCATION_ADHOC' => 'FALSE', + 'TAS_TRANSFER_FLY' => 'FALSE', + 'TAS_LAST_ASSIGNED' => 0, + 'TAS_USER' => 0, + 'TAS_CAN_UPLOAD' => 'FALSE', + 'TAS_CAN_CANCEL' => 'FALSE', + 'TAS_OWNER_APP' => 'FALSE', + 'TAS_CAN_SEND_MESSAGE' => 'FALSE', + 'TAS_SEND_LAST_EMAIL' => 'FALSE', + ]; +}); \ No newline at end of file diff --git a/database/factories/TaskUserFactory.php b/database/factories/TaskUserFactory.php new file mode 100644 index 000000000..a4c0a5e7d --- /dev/null +++ b/database/factories/TaskUserFactory.php @@ -0,0 +1,16 @@ +define(\ProcessMaker\Model\TaskUser::class, function(Faker $faker) { + return [ + 'TAS_UID' => function() { + $task = factory(\ProcessMaker\Model\Task::class)->create(); + return $task->TAS_UID; + }, + 'TU_TYPE' => 1, + 'TU_RELATION' => 1 + ]; +}); \ No newline at end of file diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php new file mode 100644 index 000000000..1885c421e --- /dev/null +++ b/database/factories/UserFactory.php @@ -0,0 +1,19 @@ +define(\ProcessMaker\Model\User::class, function(Faker $faker) { + return [ + 'USR_UID' => G::generateUniqueID(), + 'USR_USERNAME' => $faker->unique()->userName, + 'USR_PASSWORD' => $faker->password, + 'USR_FIRSTNAME' => $faker->firstName, + 'USR_LASTNAME' => $faker->lastName, + 'USR_EMAIL' => $faker->unique()->email, + 'USR_DUE_DATE' => new \Carbon\Carbon(2030,1,1), + 'USR_STATUS' => 'ACTIVE', + 'USR_ROLE' => $faker->randomElement(['PROCESSMAKER_ADMIN', 'PROCESSMAKER_OPERATOR']), + 'USR_UX' => 'NORMAL', + 'USR_TIME_ZONE' => 'America/Anguilla', + 'USR_DEFAULT_LANG' => 'en', + ]; +}); \ No newline at end of file diff --git a/framework/src/Maveriks/Extension/Restler/UploadFormat.php b/framework/src/Maveriks/Extension/Restler/UploadFormat.php index be0e01655..5f85d8ebd 100644 --- a/framework/src/Maveriks/Extension/Restler/UploadFormat.php +++ b/framework/src/Maveriks/Extension/Restler/UploadFormat.php @@ -2,6 +2,7 @@ namespace Luracast\Restler\Format; use Luracast\Restler\RestException; +use ProcessMaker\Validation\ValidationUploadedFiles; /** * Extending UploadFormat Support for Multi Part Form Data and File Uploads @@ -84,8 +85,21 @@ class UploadFormat extends Format throw new RestException(500, 'UploadFormat is read only'); } + /** + * Decode request. + * + * @param mixed $data + * @return array + * @throws RestException + * + * @see Luracast\Restler\CommentParser->parseEmbeddedData() + */ public function decode($data) { + $runRulesForFileEmpty = ValidationUploadedFiles::getValidationUploadedFiles()->runRulesForFileEmpty(); + if ($runRulesForFileEmpty->fails()) { + throw new RestException($runRulesForFileEmpty->getStatus(), $runRulesForFileEmpty->getMessage()); + } $doMimeCheck = !empty(self::$allowedMimeTypes); $doSizeCheck = self::$maximumFileSize ? TRUE : FALSE; //validate diff --git a/framework/src/Maveriks/WebApplication.php b/framework/src/Maveriks/WebApplication.php index 8b93a5a28..d619ecb8d 100644 --- a/framework/src/Maveriks/WebApplication.php +++ b/framework/src/Maveriks/WebApplication.php @@ -3,6 +3,7 @@ namespace Maveriks; use Bootstrap; +use Exception; use G; use Illuminate\Foundation\Http\Kernel; use Luracast\Restler\Format\UploadFormat; @@ -426,6 +427,16 @@ class WebApplication ); } + /** + * Define constants, setup configuration and initialize Laravel + * + * @param string $workspace + * @return bool + * @throws Exception + * + * @see run() + * @see workflow/engine/bin/cli.php + */ public function loadEnvironment($workspace = "") { define("PATH_SEP", DIRECTORY_SEPARATOR); @@ -467,24 +478,11 @@ class WebApplication define("PATH_CONTROLLERS", PATH_CORE . "controllers" . PATH_SEP); define("PATH_SERVICES_REST", PATH_CORE . "services" . PATH_SEP . "rest" . PATH_SEP); - G::defineConstants(); - $arraySystemConfiguration = System::getSystemConfiguration(); - - ini_set('date.timezone', $arraySystemConfiguration['time_zone']); //Set Time Zone - // set include path - set_include_path( - PATH_CORE . PATH_SEPARATOR . - PATH_THIRDPARTY . PATH_SEPARATOR . - PATH_THIRDPARTY . "pear" . PATH_SEPARATOR . - PATH_RBAC_CORE . PATH_SEPARATOR . - get_include_path() - ); - /* * Setting Up Workspace */ if (!file_exists(FILE_PATHS_INSTALLED)) { - throw new \Exception("Can't locate system file: " . FILE_PATHS_INSTALLED); + throw new Exception("Can't locate system file: " . FILE_PATHS_INSTALLED); } // include the server installed configuration @@ -496,17 +494,58 @@ class WebApplication define("PATH_TEMPORAL", PATH_C . "dynEditor/"); define("PATH_DB", PATH_DATA . "sites" . PATH_SEP); + // set include path + set_include_path( + PATH_CORE . PATH_SEPARATOR . + PATH_THIRDPARTY . PATH_SEPARATOR . + PATH_THIRDPARTY . "pear" . PATH_SEPARATOR . + PATH_RBAC_CORE . PATH_SEPARATOR . + get_include_path() + ); + + G::defineConstants(); + + $arraySystemConfiguration = System::getSystemConfiguration('', '', $workspace); + + //In community version the default value is 0 + $_SESSION['__SYSTEM_UTC_TIME_ZONE__'] = (int)($arraySystemConfiguration['system_utc_time_zone']) == 1; + + define('DEBUG_SQL_LOG', $arraySystemConfiguration['debug_sql']); + define('DEBUG_TIME_LOG', $arraySystemConfiguration['debug_time']); + define('DEBUG_CALENDAR_LOG', $arraySystemConfiguration['debug_calendar']); + define('MEMCACHED_ENABLED', $arraySystemConfiguration['memcached']); + define('MEMCACHED_SERVER', $arraySystemConfiguration['memcached_server']); + define('SYS_SKIN', $arraySystemConfiguration['default_skin']); + define('DISABLE_DOWNLOAD_DOCUMENTS_SESSION_VALIDATION', $arraySystemConfiguration['disable_download_documents_session_validation']); + define('TIME_ZONE', + (isset($_SESSION['__SYSTEM_UTC_TIME_ZONE__']) && $_SESSION['__SYSTEM_UTC_TIME_ZONE__']) ? 'UTC' : $arraySystemConfiguration['time_zone']); + // Change storage path app()->useStoragePath(realpath(PATH_DATA)); app()->make(Kernel::class)->bootstrap(); restore_error_handler(); error_reporting(error_reporting() & ~E_STRICT & ~E_DEPRECATED); + //Overwrite with the Processmaker env.ini configuration used in production environments + //@todo: move env.ini configuration to .env + ini_set('display_errors', $arraySystemConfiguration['display_errors']); + ini_set('error_reporting', $arraySystemConfiguration['error_reporting']); + ini_set('short_open_tag', 'On'); //?? + ini_set('default_charset', 'UTF-8'); //?? + ini_set('memory_limit', $arraySystemConfiguration['memory_limit']); + ini_set('soap.wsdl_cache_enabled', $arraySystemConfiguration['wsdl_cache']); + ini_set('date.timezone', TIME_ZONE); //Set Time Zone + + date_default_timezone_set(TIME_ZONE); + + config(['app.timezone' => TIME_ZONE]); + Bootstrap::setLanguage(); Bootstrap::LoadTranslationObject((defined("SYS_LANG")) ? SYS_LANG : "en"); if (empty($workspace)) { + // If the workspace is empty the function should be return the control to the previous file return true; } @@ -520,24 +559,6 @@ class WebApplication exit(0); } - $arraySystemConfiguration = System::getSystemConfiguration('', '', config("system.workspace")); - - //Do not change any of these settings directly, use env.ini instead - ini_set('display_errors', $arraySystemConfiguration['display_errors']); - ini_set('error_reporting', $arraySystemConfiguration['error_reporting']); - ini_set('short_open_tag', 'On'); //?? - ini_set('default_charset', 'UTF-8'); //?? - ini_set('memory_limit', $arraySystemConfiguration['memory_limit']); - ini_set('soap.wsdl_cache_enabled', $arraySystemConfiguration['wsdl_cache']); - - define('DEBUG_SQL_LOG', $arraySystemConfiguration['debug_sql']); - define('DEBUG_TIME_LOG', $arraySystemConfiguration['debug_time']); - define('DEBUG_CALENDAR_LOG', $arraySystemConfiguration['debug_calendar']); - define('MEMCACHED_ENABLED', $arraySystemConfiguration['memcached']); - define('MEMCACHED_SERVER', $arraySystemConfiguration['memcached_server']); - define('SYS_SKIN', $arraySystemConfiguration['default_skin']); - define('DISABLE_DOWNLOAD_DOCUMENTS_SESSION_VALIDATION', $arraySystemConfiguration['disable_download_documents_session_validation']); - require_once(PATH_DB . config("system.workspace") . "/db.php"); // defining constant for workspace shared directory @@ -591,17 +612,6 @@ class WebApplication \Propel::init(PATH_CONFIG . "databases.php"); - //Set Time Zone - /*----------------------------------********---------------------------------*/ - if (\PMLicensedFeatures::getSingleton()->verifyfeature('oq3S29xemxEZXJpZEIzN01qenJUaStSekY4cTdJVm5vbWtVM0d4S2lJSS9qUT0=')) { - $_SESSION['__SYSTEM_UTC_TIME_ZONE__'] = (int) ($arraySystemConfiguration['system_utc_time_zone']) == 1; - } - /*----------------------------------********---------------------------------*/ - - ini_set('date.timezone', (isset($_SESSION['__SYSTEM_UTC_TIME_ZONE__']) && $_SESSION['__SYSTEM_UTC_TIME_ZONE__']) ? 'UTC' : $arraySystemConfiguration['time_zone']); //Set Time Zone - - define('TIME_ZONE', ini_get('date.timezone')); - $oPluginRegistry = PluginRegistry::loadSingleton(); $attributes = $oPluginRegistry->getAttributes(); Bootstrap::LoadTranslationPlugins(defined('SYS_LANG') ? SYS_LANG : "en", $attributes); @@ -626,7 +636,7 @@ class WebApplication } return (isset($arrayConfig["api"]["version"]))? $arrayConfig["api"]["version"] : "1.0"; - } catch (\Exception $e) { + } catch (Exception $e) { throw $e; } } diff --git a/gulliver/js/ext/min/ext-all.js b/gulliver/js/ext/min/ext-all.js index fc8d2523c..157fc1e90 100644 --- a/gulliver/js/ext/min/ext-all.js +++ b/gulliver/js/ext/min/ext-all.js @@ -13,12 +13,12 @@ this.warning=function(title,msg,fn){Ext.MessageBox.show({id:'warningMessageBox', this.error=function(title,msg,fn){Ext.MessageBox.show({id:'errorMessageBox',title:title,msg:msg,buttons:Ext.MessageBox.OK,animEl:'mb9',fn:fn!=undefined?fn:function(){},icon:Ext.MessageBox.ERROR});} this.notify=function(title,msg,type,time) {Ext.msgBoxSlider.msg(title,msg,type,time);} -this.getBrowser=function() -{var browsersList=new Array("opera","msie","firefox","chrome","safari");var browserMeta=navigator.userAgent.toLowerCase();var name='Unknown';var version='';var screen={width:Ext.getBody().getViewSize().width,height:Ext.getBody().getViewSize().height};var so=Ext.isLinux?'Linux':(Ext.isWindows?'Windows':(Ext.isMac?'Mac OS':'Unknown'));for(var i=0;i"+v+"";},align:"right"},{width:valueColumnWidth,dataIndex:"value",renderer:function(v){return""+v+"";}},{hidden:true,dataIndex:"section"}],autoHeight:true,columnLines:true,trackMouseOver:false,disableSelection:true,view:new Ext.grid.GroupingView({forceFit:true,headersDisabled:true,groupTextTpl:'{group}'}),loadMask:true});};this.cookie={create:function(name,value,days){if(days){var date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));var expires="; expires="+date.toGMTString();}else var expires="";document.cookie=name+"="+value+expires+"; path=/";},read:function(name){var nameEQ=name+"=";var ca=document.cookie.split(';');for(var i=0;i','
','

',t,'

',s,'
','
',''].join('');} return{msg:function(title,format,type,time){if(!msgCt){msgCt=Ext.DomHelper.insertFirst(document.body,{id:'msg-div',style:'position:absolute'},true);} var s=String.format.apply(String,Array.prototype.slice.call(arguments,1));var m=Ext.DomHelper.append(msgCt,{html:createBox(title,s)},true);m.setWidth(400);m.position(null,5000);m.alignTo(document,'br-br');type=typeof type!='undefined'?type:'';time=typeof time!='undefined'?time:PMExt.notify_time_out;switch(type){case'alert':case'warning':case'tmp-warning':image='/images/alert.gif';break;case'error':case'tmp-error':image='/images/error.png';break;case'tmp-info':case'info':image='/images/info.png';break;case'success':case'ok':image='/images/select-icon.png';break;default:image='';} @@ -69,8 +69,8 @@ function getBrowserTimeZoneOffset() {return-1*((new Date()).getTimezoneOffset()*60);} function setExtStateManagerSetProvider(cache,additionalPrefix){var workspace='ws-undefined';var pathname=location.pathname.split('/');var cookieProvider=new Ext.state.CookieProvider();var i;if(additionalPrefix===undefined){additionalPrefix='';} if(pathname.length>1){workspace=pathname[1].replace('sys','');} -workspace=workspace+additionalPrefix;cookieProvider.on('statechange',function(provider,key,value){if(value!==null&&JSON.stringify(Ext.state.Manager.get(workspace+cache))!==JSON.stringify(value)){Ext.state.Manager.set(workspace+cache,value);}});Ext.state.Manager.setProvider(cookieProvider);Ext.state.Manager.clear(cache);try{if(window.extJsViewState!==undefined){for(i in extJsViewState){Ext.state.Manager.clear(i);} -Ext.state.Manager.set(cache,Ext.state.Manager.getProvider().decodeValue(extJsViewState[workspace+cache]));}}catch(e){}} +workspace=workspace+additionalPrefix;cookieProvider.on('statechange',function(provider,key,value){if(value!==null&&JSON.stringify(Ext.state.Manager.get(workspace+window.userUid+cache))!==JSON.stringify(value)){Ext.state.Manager.set(workspace+window.userUid+cache,value);}});Ext.state.Manager.setProvider(cookieProvider);Ext.state.Manager.clear(cache);try{if(window.extJsViewState!==undefined){for(i in extJsViewState){Ext.state.Manager.clear(i);} +Ext.state.Manager.set(cache,Ext.state.Manager.getProvider().decodeValue(extJsViewState[workspace+window.userUid+cache]));}}catch(e){}} function downloadFile(method,url,headers,formData,callBack){var xhr,win=window,value='blob',loadingFile=new Ext.LoadMask(Ext.getBody(),{msg:_('ID_LOADING')});method=method||'POST';loadingFile.show();if(win.XMLHttpRequest){xhr=new XMLHttpRequest();}else if(win.ActiveXObject){xhr=new ActiveXObject('Microsoft.XMLHTTP');} win.URL=win.URL||win.webkitURL;xhr.open(method,url,true);xhr.responseType=value;Object.keys(headers).forEach(function(key){xhr.setRequestHeader(key,headers[key]);});xhr.onload=function(e){loadingFile.hide();if(xhr.status===200){if(xhr.getResponseHeader("Content-Disposition")!==null){var fileName=xhr.getResponseHeader("Content-Disposition").match(/\sfilename="([^"]+)"(\s|$)/)[1];var blob=xhr.response;if((navigator.userAgent.indexOf("MSIE")!==-1)||(navigator.userAgent.indexOf("Trident")!==-1)||(navigator.userAgent.indexOf("Edge")!==-1)){win.navigator.msSaveBlob(blob,fileName);}else{var doc=win.document,a=doc.createElementNS('http://www.w3.org/1999/xhtml','a'),event=doc.createEvent('MouseEvents');event.initMouseEvent('click',true,false,win,0,0,0,0,0,false,false,false,false,0,null);a.href=win.URL.createObjectURL(blob);a.download=fileName;a.dispatchEvent(event);} if(typeof(callBack)!=='undefined'){callBack(xhr);}}else{PMExt.error(_('ID_ERROR'),_('ID_UNEXPECTED_ERROR_OCCURRED_PLEASE'));}}else{PMExt.error(_('ID_ERROR'),xhr.statusText);}};xhr.send(formData);} diff --git a/gulliver/js/ext/pmos-common.js b/gulliver/js/ext/pmos-common.js index 8dd02d56e..d75b8b77c 100644 --- a/gulliver/js/ext/pmos-common.js +++ b/gulliver/js/ext/pmos-common.js @@ -68,31 +68,34 @@ PMExtJSCommon = function() { { Ext.msgBoxSlider.msg(title, msg, type, time); } + //TODO we need to review how many places using this kind of validation + this.escapeHtml = function (v) { + var pre = document.createElement('pre'); + var text = document.createTextNode( v ); + pre.appendChild(text); - this.getBrowser = function() - { - var browsersList = new Array("opera", "msie", "firefox", "chrome", "safari"); - var browserMeta = navigator.userAgent.toLowerCase(); - var name = 'Unknown'; - var version = ''; - var screen = { - width : Ext.getBody().getViewSize().width, - height : Ext.getBody().getViewSize().height - }; - - var so = Ext.isLinux ? 'Linux' : ( Ext.isWindows ? 'Windows' : (Ext.isMac ? 'Mac OS' : 'Unknown') ); - - for (var i = 0; i < browsersList.length; i++){ - if ((name == "") && (browserMeta.indexOf(browsersList[i]) != -1)){ - name = browsersList[i]; - version = String(parseFloat(browserMeta.substr(browserMeta.indexOf(browsersList[i]) + browsersList[i].length + 1))); - break; - } - } - - return {name:name, version:version, screen: screen} + return pre.innerHTML; } + this.getBrowser = function () { + var browsersList = ["opera", "msie", "firefox", "chrome", "safari", "trident"], + browserMeta = navigator.userAgent.toLowerCase(), + name = 'Unknown', + version = '', + screen = { + width: Ext.getBody().getViewSize().width, + height: Ext.getBody().getViewSize().height + }; + for (var i = 0; i < browsersList.length; i++) { + if ((name === "") && (browserMeta.indexOf(browsersList[i]) !== -1)) { + name = browsersList[i]; + version = String(parseFloat(browserMeta.substr(browserMeta.indexOf(browsersList[i]) + browsersList[i].length + 1))); + break; + } + } + return {name: name, version: version, screen: screen} + }; + this.createInfoPanel = function (url, params, columnsSize) { var labelColumnWidth = 170; var valueColumnWidth = 350; @@ -175,7 +178,29 @@ PMExtJSCommon = function() { Tools.createCookie(name,"",-1); } } - + this.emailConst = { + appMsgTypeWithoutTask:['EXTERNAL_REGISTRATION','TEST','CASE_NOTE','SOAP','RETRIEVE_PASSWORD'], + appMsgTypeWithConditionalTask:['PM_FUNCTION'], + appMsgTypeWithoutCase:['EXTERNAL_REGISTRATION','TEST','RETRIEVE_PASSWORD'], + appMsgTypeWithoutProcess:['EXTERNAL_REGISTRATION','TEST','RETRIEVE_PASSWORD'], + appMsgTypeWithoutNumber:['EXTERNAL_REGISTRATION','TEST','RETRIEVE_PASSWORD'], + numberColumn:{ + name:'APP_NUMBER', + defaultValue:'N/A' + }, + taskColumn:{ + name:'TAS_TITLE', + defaultValue:'N/A' + }, + caseColumn:{ + name:'APP_TITLE', + defaultValue:'N/A' + }, + processColumn:{ + name:'PRO_TITLE', + defaultValue:'N/A' + } + } } var PMExt = new PMExtJSCommon(); @@ -562,11 +587,11 @@ function getBrowserTimeZoneOffset() } /** - * This is the global state manager. By default all components that are - * "state aware" check this class for state information if you don't pass them a - * custom state provider. In order for this class to be useful, it must be + * This is the global state manager. By default all components that are + * "state aware" check this class for state information if you don't pass them a + * custom state provider. In order for this class to be useful, it must be * initialized with a provider when your application initializes. - * + * * @param {string} cache * @param {string} additionalPrefix * @returns {undefined} @@ -584,8 +609,8 @@ function setExtStateManagerSetProvider(cache, additionalPrefix) { } workspace = workspace + additionalPrefix; cookieProvider.on('statechange', function (provider, key, value) { - if (value !== null && JSON.stringify(Ext.state.Manager.get(workspace + cache)) !== JSON.stringify(value)) { - Ext.state.Manager.set(workspace + cache, value); + if (value !== null && JSON.stringify(Ext.state.Manager.get(workspace + window.userUid + cache)) !== JSON.stringify(value)) { + Ext.state.Manager.set(workspace + window.userUid + cache, value); } }); Ext.state.Manager.setProvider(cookieProvider); @@ -595,7 +620,7 @@ function setExtStateManagerSetProvider(cache, additionalPrefix) { for (i in extJsViewState) { Ext.state.Manager.clear(i); } - Ext.state.Manager.set(cache, Ext.state.Manager.getProvider().decodeValue(extJsViewState[workspace + cache])); + Ext.state.Manager.set(cache, Ext.state.Manager.getProvider().decodeValue(extJsViewState[workspace + window.userUid + cache])); } } catch (e) { } diff --git a/gulliver/js/form/core/form.js b/gulliver/js/form/core/form.js index 3c5d1e24f..30878c613 100644 --- a/gulliver/js/form/core/form.js +++ b/gulliver/js/form/core/form.js @@ -346,71 +346,70 @@ function G_Text(form, element, name) this.parent = G_Field; this.browser = {}; this.comma_separator = "."; - - this.checkBrowser = function(){ - var nVer = navigator.appVersion; - var nAgt = navigator.userAgent; - //alert(navigator.userAgent); - var browserName = navigator.appName; - var fullVersion = ''+parseFloat(navigator.appVersion); - var majorVersion = parseInt(navigator.appVersion,10); - var nameOffset,verOffset,ix; + /** + * Gets the user client browser and its version + */ + this.checkBrowser = function () { + var nAgt = navigator.userAgent.toLowerCase(), + browserName = navigator.appName, + fullVersion = '' + parseFloat(navigator.appVersion), + majorVersion, + nameOffset, + verOffset, + ix; // In Opera, the true version is after "Opera" or after "Version" - if ((verOffset=nAgt.indexOf("Opera"))!=-1) { - browserName = "Opera"; - fullVersion = nAgt.substring(verOffset+6); - if ((verOffset=nAgt.indexOf("Version"))!=-1) - fullVersion = nAgt.substring(verOffset+8); - } - // In MSIE, the true version is after "MSIE" in userAgent - else if ((verOffset=nAgt.indexOf("MSIE"))!=-1) { - browserName = "Microsoft Internet Explorer"; - fullVersion = nAgt.substring(verOffset+5); - } - // In Chrome, the true version is after "Chrome" - else if ((verOffset=nAgt.indexOf("Chrome"))!=-1) { - browserName = "Chrome"; - fullVersion = nAgt.substring(verOffset+7); - } - // In Safari, the true version is after "Safari" or after "Version" - else if ((verOffset=nAgt.indexOf("Safari"))!=-1) { - browserName = "Safari"; - fullVersion = nAgt.substring(verOffset+7); - if ((verOffset=nAgt.indexOf("Version"))!=-1) - fullVersion = nAgt.substring(verOffset+8); - } - // In Firefox, the true version is after "Firefox" - else if ((verOffset=nAgt.indexOf("Firefox"))!=-1) { - browserName = "Firefox"; - fullVersion = nAgt.substring(verOffset+8); - } - // In most other browsers, "name/version" is at the end of userAgent - else if ( (nameOffset=nAgt.lastIndexOf(' ')+1) < - (verOffset=nAgt.lastIndexOf('/')) ) - { - browserName = nAgt.substring(nameOffset,verOffset); - fullVersion = nAgt.substring(verOffset+1); - if (browserName.toLowerCase()==browserName.toUpperCase()) { - browserName = navigator.appName; - } + if ((verOffset = nAgt.indexOf("opera")) !== -1) { + browserName = "Opera"; + fullVersion = nAgt.substring(verOffset + 6); + if ((verOffset = nAgt.indexOf("version")) !== -1) { + fullVersion = nAgt.substring(verOffset + 8); + } + // In MSIE, the true version is after "MSIE" or "Trident" in userAgent + } else if ((verOffset = nAgt.indexOf("msie")) !== -1 || (verOffset = nAgt.indexOf("trident")) !== -1) { + browserName = "Microsoft Internet Explorer"; + fullVersion = nAgt.substring(verOffset + 5); + // In Chrome, the true version is after "Chrome" + } else if ((verOffset = nAgt.indexOf("chrome")) !== -1) { + browserName = "Chrome"; + fullVersion = nAgt.substring(verOffset + 7); + // In Safari, the true version is after "Safari" or after "Version" + } else if ((verOffset = nAgt.indexOf("safari")) !== -1) { + browserName = "Safari"; + fullVersion = nAgt.substring(verOffset + 7); + if ((verOffset = nAgt.indexOf("version")) !== -1) + fullVersion = nAgt.substring(verOffset + 8); + // In Firefox, the true version is after "Firefox" + } else if ((verOffset = nAgt.indexOf("firefox")) !== -1) { + browserName = "Firefox"; + fullVersion = nAgt.substring(verOffset + 8); + // In most other browsers, "name/version" is at the end of userAgent + } else if ((nameOffset = nAgt.lastIndexOf(' ') + 1) < + (verOffset = nAgt.lastIndexOf('/'))) { + browserName = nAgt.substring(nameOffset, verOffset); + fullVersion = nAgt.substring(verOffset + 1); + if (browserName.toLowerCase() === browserName.toUpperCase()) { + browserName = navigator.appName; + } } // trim the fullVersion string at semicolon/space if present - if ((ix=fullVersion.indexOf(";"))!=-1) - fullVersion=fullVersion.substring(0,ix); - if ((ix=fullVersion.indexOf(" "))!=-1) - fullVersion=fullVersion.substring(0,ix); + if ((ix = fullVersion.indexOf(";")) !== -1) { + fullVersion = fullVersion.substring(0, ix); + } + if ((ix = fullVersion.indexOf(" ")) !== -1) { + fullVersion = fullVersion.substring(0, ix); + } - majorVersion = parseInt(''+fullVersion,10); + majorVersion = parseInt('' + fullVersion, 10); if (isNaN(majorVersion)) { - fullVersion = ''+parseFloat(navigator.appVersion); - majorVersion = parseInt(navigator.appVersion,10); + fullVersion = '' + parseFloat(navigator.appVersion); + majorVersion = parseInt(navigator.appVersion, 10); } this.browser = { - name: browserName, - fullVersion: fullVersion, - majorVersion: majorVersion, - userAgent: navigator.userAgent + name: browserName, + fullVersion: fullVersion, + majorVersion: majorVersion, + userAgent: navigator.userAgent }; }; @@ -3227,7 +3226,7 @@ var validateForm = function(sRequiredFields) { var systemMessaggeInvalid = ""; if(invalid_fields.length > 0) { - systemMessaggeInvalid += "\n \n" + _('ID_REQUIRED_FIELDS_GRID'); + systemMessaggeInvalid += "\n \n" + _('ID_REQUIRED_FIELDS_GRID'); } if(fielEmailInvalid.length > 0) { diff --git a/gulliver/js/maborak/core/maborak.js b/gulliver/js/maborak/core/maborak.js index 1c54b8656..324f9723e 100644 --- a/gulliver/js/maborak/core/maborak.js +++ b/gulliver/js/maborak/core/maborak.js @@ -920,18 +920,11 @@ function G_DropDown(form,element,name) {var me=this;this.parent=G_Field;this.parent(form,element,name);this.setContent=function(content) {dropDownSetOption(me,content);};if(!element)return;leimnud.event.add(this.element,'change',this.updateDepententFields);} G_DropDown.prototype=new G_Field();function G_Text(form,element,name) -{var me=this;this.mType="text";this.parent=G_Field;this.browser={};this.comma_separator=".";this.checkBrowser=function(){var nVer=navigator.appVersion;var nAgt=navigator.userAgent;var browserName=navigator.appName;var fullVersion=''+parseFloat(navigator.appVersion);var majorVersion=parseInt(navigator.appVersion,10);var nameOffset,verOffset,ix;if((verOffset=nAgt.indexOf("Opera"))!=-1){browserName="Opera";fullVersion=nAgt.substring(verOffset+6);if((verOffset=nAgt.indexOf("Version"))!=-1) -fullVersion=nAgt.substring(verOffset+8);} -else if((verOffset=nAgt.indexOf("MSIE"))!=-1){browserName="Microsoft Internet Explorer";fullVersion=nAgt.substring(verOffset+5);} -else if((verOffset=nAgt.indexOf("Chrome"))!=-1){browserName="Chrome";fullVersion=nAgt.substring(verOffset+7);} -else if((verOffset=nAgt.indexOf("Safari"))!=-1){browserName="Safari";fullVersion=nAgt.substring(verOffset+7);if((verOffset=nAgt.indexOf("Version"))!=-1) -fullVersion=nAgt.substring(verOffset+8);} -else if((verOffset=nAgt.indexOf("Firefox"))!=-1){browserName="Firefox";fullVersion=nAgt.substring(verOffset+8);} -else if((nameOffset=nAgt.lastIndexOf(' ')+1)<(verOffset=nAgt.lastIndexOf('/'))) -{browserName=nAgt.substring(nameOffset,verOffset);fullVersion=nAgt.substring(verOffset+1);if(browserName.toLowerCase()==browserName.toUpperCase()){browserName=navigator.appName;}} -if((ix=fullVersion.indexOf(";"))!=-1) -fullVersion=fullVersion.substring(0,ix);if((ix=fullVersion.indexOf(" "))!=-1) -fullVersion=fullVersion.substring(0,ix);majorVersion=parseInt(''+fullVersion,10);if(isNaN(majorVersion)){fullVersion=''+parseFloat(navigator.appVersion);majorVersion=parseInt(navigator.appVersion,10);} +{var me=this;this.mType="text";this.parent=G_Field;this.browser={};this.comma_separator=".";this.checkBrowser=function(){var nAgt=navigator.userAgent.toLowerCase(),browserName=navigator.appName,fullVersion=''+parseFloat(navigator.appVersion),majorVersion,nameOffset,verOffset,ix;if((verOffset=nAgt.indexOf("opera"))!==-1){browserName="Opera";fullVersion=nAgt.substring(verOffset+6);if((verOffset=nAgt.indexOf("version"))!==-1){fullVersion=nAgt.substring(verOffset+8);}}else if((verOffset=nAgt.indexOf("msie"))!==-1||(verOffset=nAgt.indexOf("trident"))!==-1){browserName="Microsoft Internet Explorer";fullVersion=nAgt.substring(verOffset+5);}else if((verOffset=nAgt.indexOf("chrome"))!==-1){browserName="Chrome";fullVersion=nAgt.substring(verOffset+7);}else if((verOffset=nAgt.indexOf("safari"))!==-1){browserName="Safari";fullVersion=nAgt.substring(verOffset+7);if((verOffset=nAgt.indexOf("version"))!==-1) +fullVersion=nAgt.substring(verOffset+8);}else if((verOffset=nAgt.indexOf("firefox"))!==-1){browserName="Firefox";fullVersion=nAgt.substring(verOffset+8);}else if((nameOffset=nAgt.lastIndexOf(' ')+1)<(verOffset=nAgt.lastIndexOf('/'))){browserName=nAgt.substring(nameOffset,verOffset);fullVersion=nAgt.substring(verOffset+1);if(browserName.toLowerCase()===browserName.toUpperCase()){browserName=navigator.appName;}} +if((ix=fullVersion.indexOf(";"))!==-1){fullVersion=fullVersion.substring(0,ix);} +if((ix=fullVersion.indexOf(" "))!==-1){fullVersion=fullVersion.substring(0,ix);} +majorVersion=parseInt(''+fullVersion,10);if(isNaN(majorVersion)){fullVersion=''+parseFloat(navigator.appVersion);majorVersion=parseInt(navigator.appVersion,10);} this.browser={name:browserName,fullVersion:fullVersion,majorVersion:majorVersion,userAgent:navigator.userAgent};};this.parent(form,element,name);if(element){this.prev=element.value;} this.validate='Any';this.mask='';this.required=false;this.formula='';this.key_Change=false;var doubleChange=false;function IsUnsignedInteger(YourNumber){var Template=/^d+$/;return(Template.test(YourNumber))?1:0;} function replaceAll(text,busca,reemplaza){while(text.toString().indexOf(busca)!=-1){text=text.toString().replace(busca,reemplaza);} diff --git a/gulliver/system/class.bootstrap.php b/gulliver/system/class.bootstrap.php index 4b1bd7c44..a192f0b27 100644 --- a/gulliver/system/class.bootstrap.php +++ b/gulliver/system/class.bootstrap.php @@ -207,7 +207,7 @@ class Bootstrap * = local path * @return boolean */ - public function virtualURI($url, $convertionTable, &$realPath) + public static function virtualURI($url, $convertionTable, &$realPath) { foreach ($convertionTable as $urlPattern => $localPath) { // $urlPattern = addcslashes( $urlPattern , '/'); @@ -240,7 +240,7 @@ class Bootstrap * @param string $downloadFileName * @return string */ - public function streamFile($file, $download = false, $downloadFileName = '', $forceLoad = false) + public static function streamFile($file, $download = false, $downloadFileName = '', $forceLoad = false) { $filter = new InputFilter(); $file = $filter->xssFilterHard($file); @@ -399,7 +399,7 @@ class Bootstrap * nameWorkspace to specific workspace * return true if the file exists, otherwise false. */ - public function isPMUnderUpdating($setFlag = 2, $content="true") + public static function isPMUnderUpdating($setFlag = 2, $content="true") { if (!defined('PATH_DATA')) { return false; @@ -438,7 +438,7 @@ class Bootstrap * array containig the template data * @return $content string containing the parsed template content */ - public function parseTemplate($template, $data = array()) + public static function parseTemplate($template, $data = array()) { $content = ''; @@ -556,7 +556,7 @@ class Bootstrap * @param string $strSkin * @return void */ - public function RenderPage($strTemplate = "default", $strSkin = SYS_SKIN, $objContent = null, $layout = '') + public static function RenderPage($strTemplate = "default", $strSkin = SYS_SKIN, $objContent = null, $layout = '') { global $G_CONTENT; global $G_TEMPLATE; @@ -617,7 +617,7 @@ class Bootstrap * * @return void */ - public function SendTemporalMessage($msgID, $strType, $sType = 'LABEL', $time = null, $width = null, $customLabels = null) + public static function SendTemporalMessage($msgID, $strType, $sType = 'LABEL', $time = null, $width = null, $customLabels = null) { if (isset($width)) { $_SESSION ['G_MESSAGE_WIDTH'] = $width; @@ -653,7 +653,7 @@ class Bootstrap * @param string $parameter * @return string */ - public function header($parameter) + public static function header($parameter) { if (defined('ENABLE_ENCRYPT') && (ENABLE_ENCRYPT == 'yes') && (substr($parameter, 0, 9) == 'location:')) { $url = Bootstrap::encrypt(substr($parameter, 10), URL_KEY); @@ -673,7 +673,7 @@ class Bootstrap * @access public * @return void */ - public function LoadAllPluginModelClasses() + public static function LoadAllPluginModelClasses() { // Get the current Include path, where the plugins directories should be if (!defined('PATH_SEPARATOR')) { @@ -723,7 +723,7 @@ class Bootstrap /** * function to calculate the time used to render a page */ - public function logTimeByPage() + public static function logTimeByPage() { if (!defined(PATH_DATA)) { return false; @@ -748,7 +748,7 @@ class Bootstrap * @param string $downloadFileName * @return string */ - public function streamJSTranslationFile($filename, $locale = 'en') + public static function streamJSTranslationFile($filename, $locale = 'en') { $typearray = explode('.', basename($filename)); $typeCount = count($typearray); @@ -808,7 +808,7 @@ class Bootstrap * @param string $file * @return string */ - public function streamCSSBigFile($filename) + public static function streamCSSBigFile($filename) { header('Content-Type: text/css'); @@ -964,7 +964,7 @@ class Bootstrap * * @return void */ - public function sendHeaders($filename, $contentType = '', $download = false, $downloadFileName = '') + public static function sendHeaders($filename, $contentType = '', $download = false, $downloadFileName = '') { if ($download) { if ($downloadFileName == '') { @@ -978,7 +978,7 @@ class Bootstrap // if userAgent (BROWSER) is MSIE we need special headers to avoid MSIE // behaivor. $userAgent = strtolower($_SERVER ['HTTP_USER_AGENT']); - if (preg_match("/msie/i", $userAgent)) { + if (preg_match("/msie|trident/i", $userAgent)) { // if ( ereg("msie", $userAgent)) { header('Pragma: cache'); @@ -1115,7 +1115,7 @@ class Bootstrap * strip_slashes * @param vVar */ - public function strip_slashes($vVar) + public static function strip_slashes($vVar) { if (is_array($vVar)) { foreach ($vVar as $sKey => $vValue) { @@ -1142,7 +1142,7 @@ class Bootstrap * @param eter array data // erik: associative array within data input to replace for formatted string i.e "any messsage {replaced_label} that contains a replace label" * @return string */ - public function LoadTranslation($msgID, $lang = SYS_LANG, $data = null) + public static function LoadTranslation($msgID, $lang = SYS_LANG, $data = null) { global $translation; @@ -1182,7 +1182,7 @@ class Bootstrap * @param $pattern pattern to filter some specified files * @return array containing the recursive glob results */ - public function rglob($pattern = '*', $flags = 0, $path = '') + public static function rglob($pattern = '*', $flags = 0, $path = '') { $paths = glob($path . '*', GLOB_MARK | GLOB_ONLYDIR | GLOB_NOSORT); $files = glob($path . $pattern, $flags); @@ -1197,7 +1197,7 @@ class Bootstrap * * @author Erik A.O. */ - public function json_encode($Json) + public static function json_encode($Json) { if (function_exists('json_encode')) { return json_encode($Json); @@ -1229,7 +1229,7 @@ class Bootstrap * * @author Erik Amaru Ortiz */ - public function xmlParser(&$string) + public static function xmlParser(&$string) { $parser = xml_parser_create(); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); @@ -1304,7 +1304,7 @@ class Bootstrap * @param unknown_type $maxmtime * @return Ambigous */ - public function getDirectorySize($path, $maxmtime = 0) + public static function getDirectorySize($path, $maxmtime = 0) { $totalsize = 0; $totalcount = 0; @@ -1348,8 +1348,7 @@ class Bootstrap * * @return void */ - // _Internal: Remove recursion in result array - public function _del_p(&$ary) + public static function _del_p(&$ary) { foreach ($ary as $k => $v) { if ($k === '_p') { @@ -1365,7 +1364,7 @@ class Bootstrap * @author Ralph A. * @return multitype:array containing browser name and type */ - public function get_current_browser() + public static function get_current_browser() { static $a_full_assoc_data, $a_mobile_data, $browser_user_agent; static $browser_working, $moz_type, $webkit_type; @@ -1563,7 +1562,7 @@ class Bootstrap * @param unknown_type $pv_extra_search * @return string */ - public function get_item_version($pv_browser_user_agent, $pv_search_string, $pv_b_break_last = '', $pv_extra_search = '') + public static function get_item_version($pv_browser_user_agent, $pv_search_string, $pv_b_break_last = '', $pv_extra_search = '') { $substring_length = 15; $start_pos = 0; // set $start_pos to 0 for first iteration @@ -1594,7 +1593,7 @@ class Bootstrap * @param unknown_type $pv_type * @param unknown_type $pv_value */ - public function get_set_count($pv_type, $pv_value = '') + public static function get_set_count($pv_type, $pv_value = '') { static $slice_increment; $return_value = ''; @@ -1743,7 +1742,7 @@ class Bootstrap * @param unknown_type $pv_browser_user_agent * @return string */ - public function check_is_mobile($pv_browser_user_agent) + public static function check_is_mobile($pv_browser_user_agent) { $mobile_working_test = ''; $a_mobile_search = array( @@ -1771,7 +1770,7 @@ class Bootstrap * * @param unknown_type $pv_browser_user_agent */ - public function get_mobile_data($pv_browser_user_agent) + public static function get_mobile_data($pv_browser_user_agent) { $mobile_browser = ''; $mobile_browser_number = ''; @@ -1943,7 +1942,7 @@ class Bootstrap * @param string $key * @return string */ - public function encrypt($string, $key) + public static function encrypt($string, $key) { //print $string; // if ( defined ( 'ENABLE_ENCRYPT' ) && ENABLE_ENCRYPT == 'yes' ) { @@ -1973,7 +1972,7 @@ class Bootstrap * @param string $key * @return string */ - public function decrypt($string, $key) + public static function decrypt($string, $key) { // if ( defined ( 'ENABLE_ENCRYPT' ) && ENABLE_ENCRYPT == 'yes' ) { //if (strpos($string, '|', 0) !== false) return $string; @@ -2066,7 +2065,7 @@ class Bootstrap * @param string $array_i * @return array */ - public function array_merge_2(&$array, &$array_i) + public static function array_merge_2(&$array, &$array_i) { foreach ($array_i as $k => $v) { if (is_array($v)) { @@ -2095,7 +2094,7 @@ class Bootstrap * @return array_sum(explode(' ',microtime())) */ /* public static */ - public function microtime_float() + public static function microtime_float() { return array_sum(explode(' ', microtime())); } @@ -2344,7 +2343,7 @@ class Bootstrap * @author Erik Amaru Ortiz * @name complete_field($string, $lenght, $type={1:number/2:string/3:float}) */ - public function complete_field($campo, $long, $tipo) + public static function complete_field($campo, $long, $tipo) { $campo = trim($campo); switch ($tipo) { @@ -2580,7 +2579,7 @@ class Bootstrap * @param string $userPass hash of password * @return bool true or false */ - public function verifyHashPassword($pass, $userPass) + public static function verifyHashPassword($pass, $userPass) { global $RBAC; $passwordHashConfig = Bootstrap::getPasswordHashConfig(); @@ -2610,7 +2609,7 @@ class Bootstrap * @param $string * @return mixed */ - public function encryptOld($string) + public static function encryptOld($string) { $consthashFx = self::hashFx; return $consthashFx($string); @@ -2638,14 +2637,14 @@ class Bootstrap } /** - * Set Language + * Verify if the browser is Internet Explorer */ public static function isIE() { $isIE = false; if (isset($_SERVER['HTTP_USER_AGENT'])) { - $ua = htmlentities($_SERVER['HTTP_USER_AGENT'], ENT_QUOTES, 'UTF-8'); - if (preg_match('~MSIE|Internet Explorer~i', $ua) || (strpos($ua, 'Trident/7.0; rv:11.0') !== false)) { + $userAgent = htmlentities($_SERVER['HTTP_USER_AGENT'], ENT_QUOTES, 'UTF-8'); + if (preg_match("/(Trident\/(\d{2,}|7|8|9)(.*)rv:(\d{2,}))|(MSIE\ (\d{2,}|8|9)(.*)Tablet\ PC)|(Trident\/(\d{2,}|7|8|9))/", $userAgent)) { $isIE = true; } } @@ -2683,30 +2682,54 @@ class Bootstrap * Get the default information from the context * * @return array + * + * @see AdditionalTables->populateReportTable + * @see AppAssignSelfServiceValueGroup->createRow + * @see Bootstrap->registerMonologPhpUploadExecution() + * @see Cases->loadDataSendEmail() + * @see Cases->removeCase() + * @see Cases->reportTableDeleteRecord() + * @see Derivation->derivate + * @see G->logTriggerExecution() + * @see LdapAdvanced->VerifyLogin + * @see ldapadvancedClassCron->executeCron + * @see PmDynaform->__construct + * @see pmTablesProxy->genDataReport + * @see Processes->createFiles + * @see ProcessMaker\AuditLog\AuditLog->register + * @see ProcessMaker\Util\ParseSoapVariableName->buildVariableName + * @see RBAC->checkAutomaticRegister() + * @see workflow/engine/classes/class.pmFunctions.php::executeQuery + + * @link https://wiki.processmaker.com/3.3/Actions_by_Email + * @link https://wiki.processmaker.com/3.2/ProcessMaker_Functions + * @link https://wiki.processmaker.com/3.1/Report_Tables + * @link https://wiki.processmaker.com/3.2/Cases/Running_Cases + * @link https://wiki.processmaker.com/3.3/login + * @link https://wiki.processmaker.com/3.2/Executing_cron.php + * @link https://wiki.processmaker.com/3.2/HTML5_Responsive_DynaForm_Designer + * @link https://wiki.processmaker.com/3.2/Audit_Log + * @link https://wiki.processmaker.com/3.0/ProcessMaker_WSDL_Web_Services */ public static function getDefaultContextLog() { - - global $RBAC; $info = [ 'ip' => G::getIpAddress(), 'workspace' => !empty(config('system.workspace')) ? config('system.workspace') : 'Undefined Workspace', - 'timeZone' => DateTime::convertUtcToTimeZone(date('Y-m-d H:m:s')) + 'timeZone' => DateTime::convertUtcToTimeZone(date('Y-m-d H:m:s')), + 'usrUid' => G::LoadTranslation('UID_UNDEFINED_USER') ]; - if ($RBAC !== null) { - $userInfo = [ - 'usrUid' => $RBAC->aUserInfo['USER_INFO']['USR_UID'] - ]; - $info = array_merge($info, $userInfo); + global $RBAC; + if (!empty($RBAC) && !empty($RBAC->aUserInfo['USER_INFO']) && !empty($RBAC->aUserInfo['USER_INFO']['USR_UID'])) { + $info['usrUid'] = $RBAC->aUserInfo['USER_INFO']['USR_UID']; + return $info; } - //Some endpoints can defined the USER_LOGGED - if (empty($info['usrUid'])) { - $user = !empty($_SESSION['USER_LOGGED']) ? $_SESSION['USER_LOGGED'] : G::LoadTranslation('UID_UNDEFINED_USER'); - $userInfo = [ - 'usrUid' => $user - ]; - $info = array_merge($info, $userInfo); + + //if default session exists + if (!empty($_SESSION['USER_LOGGED'])) { + $info['usrUid'] = $_SESSION['USER_LOGGED']; + return $info; } return $info; diff --git a/gulliver/system/class.form.php b/gulliver/system/class.form.php index 9814d8e5f..96cfb7cbb 100644 --- a/gulliver/system/class.form.php +++ b/gulliver/system/class.form.php @@ -105,6 +105,10 @@ class Form extends XmlForm $filename = $filename . '.xml'; } $this->home = $home; + + //to do: This must be removed, the post validation should only be done for the classic version. + self::createXMLFileIfNotExists($this->home . $filename); + $res = parent::parseFile( $filename, $language, $forceParse ); if ($res == 1) { trigger_error( 'Faild to parse file ' . $filename . '.', E_USER_ERROR ); @@ -751,5 +755,53 @@ class Form extends XmlForm } return $data; } + + /** + * Create XML file if not exists. + * + * @param string $filepath + * + * @see Form->__construct() + * @@link https://wiki.processmaker.com/3.1/Cases + * @link https://wiki.processmaker.com/index.php/2.5.X/DynaForms#XML_tab + */ + public static function createXMLFileIfNotExists($filepath) + { + if (file_exists($filepath)) { + return; + } + $pathParts = pathinfo($filepath); + if (empty($pathParts)) { + return; + } + $dynUid = $pathParts["filename"]; + $proUid = basename($pathParts["dirname"]); + $pathHome = dirname($pathParts["dirname"]) . PATH_SEP; + self::createXMLFile($proUid, $dynUid, 'xmlform', $pathHome); + } + + /** + * Create XML file. + * + * @param string $proUid + * @param string $dynUid + * @param string $dynType + * @param string $pathHome + * + * @see Dynaform->create() + * @see Form::createXMLFileIfNotExists() + * @link https://wiki.processmaker.com/3.1/Cases + * @link https://wiki.processmaker.com/index.php/2.5.X/DynaForms#XML_tab + */ + public static function createXMLFile($proUid, $dynUid, $dynType = 'xmlform', $pathHome = PATH_XMLFORM) + { + $xml = '' . "\n"; + $xml .= '' . "\n"; + $xml .= ''; + G::verifyPath($pathHome . $proUid, true); + $file = fopen($pathHome . $proUid . '/' . $dynUid . '.xml', 'w'); + fwrite($file, $xml); + fclose($file); + } } diff --git a/gulliver/system/class.g.php b/gulliver/system/class.g.php index 5b63e720e..0b39f7d33 100644 --- a/gulliver/system/class.g.php +++ b/gulliver/system/class.g.php @@ -1360,7 +1360,7 @@ class G return $e; } - /** + /** * formatNumber * * @author David Callizaya @@ -1376,7 +1376,7 @@ class G return $snum; } - /** + /** * Returns a date formatted according to the given format string * @author David Callizaya * @param string $format The format of the outputted date string @@ -1634,15 +1634,18 @@ class G return $campo; } - /** + /** * Escapes special characters in a string for use in a SQL statement - * @param string $sqlString The string to be escaped - * @param string $DBEngine Target DBMS - */ - public function sqlEscape($sqlString, $DBEngine = DB_ADAPTER) + * @param string $sqlString The string to be escaped + * @param string $dbEngine Target DBMS + * + * @return string + */ + public static function sqlEscape($sqlString, $dbEngine = DB_ADAPTER) { - $DBEngine = DB_ADAPTER; - switch ($DBEngine) { + // @todo: Research why always this value is set with the same constant? + $dbEngine = DB_ADAPTER; + switch ($dbEngine) { case 'mysql': $con = Propel::getConnection('workflow'); return mysqli_real_escape_string($con->getResource(), stripslashes($sqlString)); @@ -1678,7 +1681,7 @@ class G } } - /** + /** * Returns a sql string with @@parameters replaced with its values defined * in array $result using the next notation: * NOTATION: @@ -1689,9 +1692,15 @@ class G * @# Non-quoted parameter * @! Evaluate string : Replace the parameters in value and then in the sql string * @fn() Evaluate string with the function "fn" - * @author David Callizaya + * + * @param string $sqlString + * @param array $result + * @param string $dbEngine + * @param bool $applyHtmlEntities + * + * @return string */ - public static function replaceDataField($sqlString, $result, $DBEngine = 'mysql') + public static function replaceDataField($sqlString, $result, $dbEngine = 'mysql', $applyHtmlEntities = false) { if (!is_array($result)) { $result = array(); @@ -1710,7 +1719,12 @@ class G $u = $match[0][$r][1] + strlen($match[0][$r][0]); //Mysql quotes scape if (($match[1][$r][0] == '@') && (isset($result[$match[2][$r][0]]))) { - $__textoEval .= "\"" . G::sqlEscape($result[$match[2][$r][0]], $DBEngine) . "\""; + $text = ($applyHtmlEntities && !stringIsValidHtml($result[$match[2][$r][0]])) ? + htmlentities(G::unhtmlentities($result[$match[2][$r][0]]), ENT_COMPAT, 'UTF-8') : + $result[$match[2][$r][0]]; + // Replenish the tag
because is valid + $text = str_replace('<br />', '
', $text); + $__textoEval .= "\"" . G::sqlEscape($text, $dbEngine) . "\""; continue; } //URL encode @@ -1730,7 +1744,7 @@ class G } //Substring (Sub replaceDataField) if (($match[1][$r][0] == '!') && (isset($result[$match[2][$r][0]]))) { - $__textoEval .= G::replaceDataField($result[$match[2][$r][0]], $result); + $__textoEval .= G::replaceDataField($result[$match[2][$r][0]], $result, $dbEngine, $applyHtmlEntities); continue; } //Call function @@ -1748,18 +1762,33 @@ class G } //Non-quoted if (($match[1][$r][0] == '#') && (isset($result[$match[2][$r][0]]))) { - $__textoEval .= G::replaceDataField($result[$match[2][$r][0]], $result); + $text = ($applyHtmlEntities && !stringIsValidHtml($result[$match[2][$r][0]])) ? + htmlentities(G::unhtmlentities($result[$match[2][$r][0]]), ENT_COMPAT, 'UTF-8') : + $result[$match[2][$r][0]]; + // Replenish the tag
because is valid + $text = str_replace('<br />', '
', $text); + $__textoEval .= G::replaceDataField($text, $result); continue; } //Non-quoted = if (($match[1][$r][0] == '=') && (isset($result[$match[2][$r][0]]))) { - $__textoEval .= G::replaceDataField($result[$match[2][$r][0]], $result); + $text = ($applyHtmlEntities && !stringIsValidHtml($result[$match[2][$r][0]])) ? + htmlentities(G::unhtmlentities($result[$match[2][$r][0]]), ENT_COMPAT, 'UTF-8') : + $result[$match[2][$r][0]]; + // Replenish the tag
because is valid + $text = str_replace('<br />', '
', $text); + $__textoEval .= G::replaceDataField($text, $result); continue; } //Objects attributes if (($match[1][$r][0] == '&') && (isset($result[$match[2][$r][0]]))) { if (isset($result[$match[2][$r][0]]->{$match[6][$r][0]})) { - $__textoEval .= $result[$match[2][$r][0]]->{$match[6][$r][0]}; + $text = ($applyHtmlEntities && !stringIsValidHtml($result[$match[2][$r][0]]->{$match[6][$r][0]})) ? + htmlentities(G::unhtmlentities($result[$match[2][$r][0]]->{$match[6][$r][0]}), ENT_COMPAT, 'UTF-8') : + $result[$match[2][$r][0]]->{$match[6][$r][0]}; + // Replenish the tag
because is valid + $text = str_replace('<br />', '
', $text); + $__textoEval .= $text; } continue; } @@ -1771,27 +1800,36 @@ class G } /** - * Replace Grid Values - * The tag @>GRID-NAME to open the grid and @GRID-NAME to open the grid and @sendMessage() + * @see \WsBase->sendMessage() + * @see \OutputDocument->generate() + * @see \ProcessMaker\BusinessModel\Cases\OutputDocument->generate() + */ + public static function replaceDataGridField($content, $fields, $nl2brRecursive = true, $applyHtmlEntities = false) { $nrt = array("\n", "\r", "\t"); $nrthtml = array("(n /)", "(r /)", "(t /)"); - $sContent = G::unhtmlentities($sContent); - $strContentAux = str_replace($nrt, $nrthtml, $sContent); + $content = G::unhtmlentities($content); + $strContentAux = str_replace($nrt, $nrthtml, $content); - $iOcurrences = preg_match_all('/\@(?:([\>])([a-zA-Z\_]\w*)|([a-zA-Z\_][\w\-\>\:]*)\(((?:[^\\\\\)]*(?:[\\\\][\w\W])?)*)\))((?:\s*\[[\'"]?\w+[\'"]?\])+)?/', $strContentAux, $arrayMatch1, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE); + $occurrences = preg_match_all('/\@(?:([\>])([a-zA-Z\_]\w*)|([a-zA-Z\_][\w\-\>\:]*)\(((?:[^\\\\\)]*(?:[\\\\][\w\W])?)*)\))((?:\s*\[[\'"]?\w+[\'"]?\])+)?/', + $strContentAux, $arrayMatch1, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE); - if ($iOcurrences) { + if ($occurrences) { $arrayGrid = array(); - for ($i = 0; $i <= $iOcurrences - 1; $i++) { + for ($i = 0; $i <= $occurrences - 1; $i++) { $arrayGrid[] = $arrayMatch1[2][$i][0]; } @@ -1817,16 +1855,16 @@ class G while (preg_match($ereg, $strContentAux1, $arrayMatch2)) { $strData = null; - if (isset($aFields[$grdName]) && is_array($aFields[$grdName])) { - foreach ($aFields[$grdName] as $aRow) { + if (isset($fields[$grdName]) && is_array($fields[$grdName])) { + foreach ($fields[$grdName] as $aRow) { if ($nl2brRecursive) { - foreach ($aRow as $sKey => $vValue) { - if (!is_array($vValue)) { - $aRow[$sKey] = str_replace($nrt, $nrthtml, nl2br($aRow[$sKey])); + foreach ($aRow as $key => $item) { + if (!is_array($item)) { + $aRow[$key] = str_replace($nrt, $nrthtml, nl2br($aRow[$key])); } } } - $strData = $strData . G::replaceDataField($arrayMatch2[2], $aRow); + $strData = $strData . G::replaceDataField($arrayMatch2[2], $aRow, 'mysql', $applyHtmlEntities); } } @@ -1841,22 +1879,22 @@ class G $strContentAux = str_replace($nrthtml, $nrt, $strContentAux); - $sContent = $strContentAux; + $content = $strContentAux; if ($nl2brRecursive) { - foreach ($aFields as $sKey => $vValue) { - if (!is_array($vValue) && !is_object($vValue)) { - $aFields[$sKey] = nl2br($aFields[$sKey]); + foreach ($fields as $key => $item) { + if (!is_array($item) && !is_object($item)) { + $fields[$key] = nl2br($fields[$key]); } } } - $sContent = G::replaceDataField($sContent, $aFields); + $content = G::replaceDataField($content, $fields, 'mysql', $applyHtmlEntities); - return $sContent; + return $content; } - /** + /** * Load strings from a XMLFile. * @author David Callizaya * @parameter $languageFile An xml language file. @@ -1895,7 +1933,7 @@ class G } } - /** + /** * Funcion auxiliar Temporal: * Registra en la base de datos los labels xml usados en el sistema * @author David Callizaya @@ -2767,7 +2805,7 @@ class G $image = $inputFn($path); imagecopyresampled($image_p, $image, 0, 0, 0, 0, $resWidth, $resHeight, $width, $height); $outputFn($image_p, $saveTo); - + if (!is_null($saveTo)) { $filter = new InputFilter(); $saveTo = $filter->validateInput($saveTo, "path"); @@ -3197,10 +3235,11 @@ class G * Inflects a string with accented characters and other characteres not suitable for file names, by defaul replace with undescore * * @author Erik Amaru Ortiz - * @param (string) string to convert - * @param (string) character for replace - * @param (array) additional characteres map - * + * @param string $string to convert + * @param string $replacement character for replace + * @param array $map additional characteres map + * @return string|string[]|null + * @see PMXPublisher::truncateName, Processes::saveSerializedProcess, XmlExporter::truncateName */ public static function inflect($string, $replacement = '_', $map = array()) { @@ -3209,8 +3248,6 @@ class G $replacement = '_'; } - $quotedReplacement = preg_quote($replacement, '/'); - $default = array('/à|á|å|â/' => 'a', '/è|é|ê|ẽ|ë/' => 'e', '/ì|í|î/' => 'i', @@ -5490,7 +5527,7 @@ class G public static function verifyInputDocExtension($InpDocAllowedFiles, $fileName, $filesTmpName) { $error = null; - ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) use(&$error) { + ValidationUploadedFiles::getValidationUploadedFiles()->dispatch(function($validator) use(&$error) { $error = new stdclass(); $error->status = false; $error->message = $validator->getMessage(); @@ -5824,7 +5861,7 @@ class G include(PATH_METHODS . "login/version-pmos.php"); } //Removed default version from code. - + /** * The constants defined comes from the file: * processmaker/workflow/engine/classes/class.plugin.php, the loading of this @@ -5893,4 +5930,25 @@ class G $class = isset(self::$adapters[$key]) ? self::$adapters[$key] : $name; return class_exists($class); } + + /** + * Fix string corrupted related to PMC-336. + * To do, this method should be removed. Related to PMC-336. + * + * @param string $string + * @return string + */ + public static function fixStringCorrupted($string) + { + $string = preg_replace_callback("/iconv\\(\\'UCS\\-4LE\\',\\'UTF\\-8\\',pack\\(\\'V\\', hexdec\\(\\'U[a-f0-9]{4}\\'\\)\\)\\)/", function($result) { + //This looks for the following pattern: + //iconv('UCS-4LE','UTF-8',pack('V', hexdec('U062f')))iconv('UCS-4LE','UTF-8',pack('V', hexdec('U0631'))) + //So making this replacement is safe. + $portion = $result[0]; + $portion = str_replace("iconv('UCS-4LE','UTF-8',pack('V', hexdec('U", "\u", $portion); + $portion = str_replace("')))", "", $portion); + return $portion; + }, $string); + return $string; + } } diff --git a/gulliver/system/class.headPublisher.php b/gulliver/system/class.headPublisher.php index 8204a05e0..b153f05a7 100644 --- a/gulliver/system/class.headPublisher.php +++ b/gulliver/system/class.headPublisher.php @@ -746,11 +746,11 @@ class headPublisher * * @return array $views */ - public function getExtJsViewState() + public function getExtJsViewState($userUid = '') { $json = new stdClass(); $views = array(); - $keyState = "extJsViewState"; + $keyState = "extJsViewState" . $userUid; $prefixExtJs = "ys-"; $oServerConf = ServerConf::getSingleton(); $deleteCache = true; diff --git a/gulliver/system/class.rbac.php b/gulliver/system/class.rbac.php index ec5634e81..79dad003c 100644 --- a/gulliver/system/class.rbac.php +++ b/gulliver/system/class.rbac.php @@ -55,7 +55,7 @@ class RBAC /** * * @access private - * @var $userObj + * @var RbacUsers $userObj */ public $userObj; public $usersPermissionsObj; @@ -803,6 +803,80 @@ class RBAC $this->aUserInfo[$sSystem]['PERMISSIONS'] = $fieldsPermissions; } + /** + * Verification of a user through the class RBAC_user + * verify if the user has permissions to stay in the application + * -4: expired user + * @access public + * @throws Exception + */ + public function verifyDueDateUserLogged() + { + if (empty($this->userObj)) { + return; + } + $uid = !empty($this->userObj) ? $this->userObj->getUsrUid() : null; + //if the expired user + if ($this->userObj->getUsrDueDate() < date('Y-m-d')) { + $uid = -4; + $errLabel = 'ID_USER_INACTIVE_BY_DATE'; + } + + if (!isset($uid) || $uid < 0) { + if (!defined('PPP_FAILED_LOGINS')) { + define('PPP_FAILED_LOGINS', 0); + } + //start new session + @session_destroy(); + session_start(); + session_regenerate_id(); + + throw new RBACException($errLabel); + } + } + + /** + * Destroy all active sessions of a user (browser, soap, oauth) + * @param string $usrUid User uid + */ + public static function destroySessionUser($usrUid) + { + //remove all register of tables related to the token + (new OauthAccessTokens())->removeByUser($usrUid); + (new OauthRefreshTokens())->removeByUser($usrUid); + (new PmoauthUserAccessTokens())->removeByUser($usrUid); + (new OauthAuthorizationCodes())->removeByUser($usrUid); + + $loginLog = new LoginLog(); + $sessionId = $loginLog->getSessionsIdByUser($usrUid); + if ($sessionId) { + //remove all login log row's of LOGIN_LOG table + $loginLog->removeByUser($usrUid); + //remove all register of tables + (new Session())->removeByUser($usrUid); + + // 1. commit session if it's started. + if (session_id()) { + session_commit(); + } + // 2. store current session id + session_start(); + $currentSessionId = session_id(); + session_commit(); + // 3. then destroy session specified. + foreach ($sessionId as $sid) { + session_id($sid['LOG_SID']); + session_start(); + session_destroy(); + session_commit(); + } + // 4. restore current session id. If don't restore it, your current session will refer to the session you just destroyed! + session_id($currentSessionId); + session_start(); + session_commit(); + } + } + /** * verification the register automatic * diff --git a/phpunit.xml b/phpunit.xml index e59678301..91b213c61 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -15,9 +15,9 @@ ./tests/workflow/engine/src/ - ./tests/Unit + ./tests/Unit - + @@ -33,31 +33,32 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 70cb1973e..fdee3691a 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,4 +1,5 @@ make(Kernel::class)->bootstrap(); // Setup our testexternal database config(['database.connections.testexternal' => [ - 'driver' => 'mysql', - 'host' => env('DB_HOST', '127.0.0.1'), - 'database' => env('DB_TESTEXTERNAL_DB', 'testexternal'), - 'username' => env('DB_USERNAME', 'root'), - 'password' => env('DB_PASSWORD', ''), - 'unix_socket' => env('DB_SOCKET', ''), - 'charset' => 'utf8mb4', - 'collation' => 'utf8mb4_unicode_ci', - 'prefix' => '', - 'strict' => true, - 'engine' => null, + 'driver' => 'mysql', + 'host' => env('DB_HOST', '127.0.0.1'), + 'database' => env('DB_DATABASE', 'testexternal'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', 'password'), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', + 'strict' => true, + 'engine' => null ]]); // Now, drop all test tables and repopulate with schema @@ -52,13 +61,13 @@ DB::connection('testexternal')->table('test')->insert([ ]); // Only do if we are supporting MSSql tests -if(env('RUN_MSSQL_TESTS')) { +if (env('RUN_MSSQL_TESTS')) { config(['database.connections.mssql' => [ - 'driver' => 'sqlsrv', - 'host' => env('MSSQL_HOST', '127.0.0.1'), - 'database' => env('MSSQL_DATABASE', 'testexternal'), - 'username' => env('MSSQL_USERNAME', 'root'), - 'password' => env('MSSQL_PASSWORD', ''), + 'driver' => 'sqlsrv', + 'host' => env('MSSQL_HOST', '127.0.0.1'), + 'database' => env('MSSQL_DATABASE', 'testexternal'), + 'username' => env('MSSQL_USERNAME', 'root'), + 'password' => env('MSSQL_PASSWORD', 'password'), ]]); Schema::connection('mssql')->dropIfExists('test'); @@ -73,26 +82,25 @@ if(env('RUN_MSSQL_TESTS')) { // THIS IS FOR STANDARD PROCESSMAKER TABLES - // Now, drop all test tables and repopulate with schema DB::unprepared('SET FOREIGN_KEY_CHECKS = 0'); $colname = 'Tables_in_' . env('DB_DATABASE'); $tables = DB::select('SHOW TABLES'); $drop = []; -foreach($tables as $table) { +foreach ($tables as $table) { $drop[] = $table->$colname; } -if(count($drop)) { +if (count($drop)) { $drop = implode(',', $drop); DB::statement("DROP TABLE $drop"); DB::unprepared('SET FOREIGN_KEY_CHECKS = 1'); } // Repopulate with schema and standard inserts -DB::unprepared(file_get_contents(PATH_CORE.'data/mysql/schema.sql')); -DB::unprepared(file_get_contents(PATH_RBAC_CORE.'data/mysql/schema.sql')); -DB::unprepared(file_get_contents(PATH_CORE.'data/mysql/insert.sql')); -DB::unprepared(file_get_contents(PATH_RBAC_CORE.'data/mysql/insert.sql')); +DB::unprepared(file_get_contents(PATH_CORE . 'data/mysql/schema.sql')); +DB::unprepared(file_get_contents(PATH_RBAC_CORE . 'data/mysql/schema.sql')); +DB::unprepared(file_get_contents(PATH_CORE . 'data/mysql/insert.sql')); +DB::unprepared(file_get_contents(PATH_RBAC_CORE . 'data/mysql/insert.sql')); // Set our APP_SEQUENCE val DB::table('APP_SEQUENCE')->insert([ @@ -106,7 +114,7 @@ DB::table('OAUTH_CLIENTS')->insert([ 'CLIENT_NAME' => 'PM Web Designer', 'CLIENT_DESCRIPTION' => 'ProcessMaker Web Designer App', 'CLIENT_WEBSITE' => 'www.processmaker.com', - 'REDIRECT_URI' => config('app.url') . '/sys' . config('system.workspace').'/en/neoclassic/oauth2/grant', + 'REDIRECT_URI' => config('app.url') . '/sys' . config('system.workspace') . '/en/neoclassic/oauth2/grant', 'USR_UID' => '00000000000000000000000000000001' ]); DB::table('OAUTH_ACCESS_TOKENS')->insert([ @@ -133,4 +141,4 @@ Propel::initConfiguration([ 'adapter' => 'mysql' ] ] -]); \ No newline at end of file +]); diff --git a/tests/unit/gulliver/system/ReplaceDataFieldTest.php b/tests/unit/gulliver/system/ReplaceDataFieldTest.php new file mode 100644 index 000000000..e4445024c --- /dev/null +++ b/tests/unit/gulliver/system/ReplaceDataFieldTest.php @@ -0,0 +1,252 @@ +value'; + $dbEngine = 'mysql'; // This only affects the way to escape the variables with "@@" prefix + $applyEntities = true; // If a value to replace is a not valid HTML and have HTML reserved characters, entities should be applied + + // Initializing variables to test the assertions, entities should be applied in variable with @@ + $var4 = new stdClass(); + $var4->value = $faker->words(1, true); + $valuesToReplace = [ + 'var1' => 'Java < PHP & Python', + 'var2' => $faker->words(1, true), + 'var3' => $faker->words(1, true), + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/</', $stringToCheck); + $this->assertRegExp('/&/', $stringToCheck); + + // Initializing variables to test the assertions, entities should be applied in variable with @# + $var4 = new stdClass(); + $var4->value = $faker->words(1, true); + $valuesToReplace = [ + 'var1' => $faker->words(1, true), + 'var2' => 'Java < PHP & Python', + 'var3' => $faker->words(1, true), + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/</', $stringToCheck); + $this->assertRegExp('/&/', $stringToCheck); + + // Initializing variables to test the assertions, entities should be applied in variable with @= + $var4 = new stdClass(); + $var4->value = $faker->words(1, true); + $valuesToReplace = [ + 'var1' => $faker->words(1, true), + 'var2' => $faker->words(1, true), + 'var3' => 'Java < PHP & Python', + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/</', $stringToCheck); + $this->assertRegExp('/&/', $stringToCheck); + + // Initializing variables to test the assertions, entities should be applied in variable with @& + $var4 = new stdClass(); + $var4->value = 'Java < PHP & Python'; + $valuesToReplace = [ + 'var1' => $faker->words(1, true), + 'var2' => $faker->words(1, true), + 'var3' => $faker->words(1, true), + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/</', $stringToCheck); + $this->assertRegExp('/&/', $stringToCheck); + } + + /** + * This checks that strings with HTML reserved characters are NOT replaced with entities + * @test + */ + public function it_should_no_replace_entities() + { + // Initializing Faker instance + $faker = Faker\Factory::create(); + + // Initializing variables to use that will not change + $stringWithVariablesToReplace = 'Hello @@var1 the @#var2 is @=var3 not @&var4->value'; + $dbEngine = 'mysql'; // This only affects the way to escape the variables with "@@" prefix + $applyEntities = false; // The values should not be replaced with entities + + // Initializing variables to test the assertions, entities should be applied in variable with @@ + $var4 = new stdClass(); + $var4->value = $faker->words(1, true); + $valuesToReplace = [ + 'var1' => 'Java < PHP & Python', + 'var2' => $faker->words(1, true), + 'var3' => $faker->words(1, true), + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/assertRegExp('/&/', $stringToCheck); + + // Initializing variables to test the assertions, entities should be applied in variable with @# + $var4 = new stdClass(); + $var4->value = $faker->words(1, true); + $valuesToReplace = [ + 'var1' => $faker->words(1, true), + 'var2' => 'Java < PHP & Python', + 'var3' => $faker->words(1, true), + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/assertRegExp('/&/', $stringToCheck); + + // Initializing variables to test the assertions, entities should be applied in variable with @= + $var4 = new stdClass(); + $var4->value = $faker->words(1, true); + $valuesToReplace = [ + 'var1' => $faker->words(1, true), + 'var2' => $faker->words(1, true), + 'var3' => 'Java < PHP & Python', + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/assertRegExp('/&/', $stringToCheck); + + // Initializing variables to test the assertions, entities should be applied in variable with @& + $var4 = new stdClass(); + $var4->value = 'Java < PHP & Python'; + $valuesToReplace = [ + 'var1' => $faker->words(1, true), + 'var2' => $faker->words(1, true), + 'var3' => $faker->words(1, true), + 'var4' => $var4 + ]; + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('/assertRegExp('/&/', $stringToCheck); + } + + /** + * This checks that strings with HTML reserved characters are NOT replaced with entities if is a valid HTML, because + * PS team sometimes build a HTML string to insert in templates (output documents or emails), Ex.- A table to list + * users or results from a query + * @test + */ + public function it_should_no_replace_entities_if_exists_valid_html() + { + // Initializing Faker instance + $faker = Faker\Factory::create(); + + // Initializing variables to use + $stringWithVariablesToReplace = 'bla @#var1 bla @=listHtml bla @@var2 bla'; + $valuesToReplace = [ + 'var1' => $faker->words(1, true), + 'listHtml' => ' + + + + + + + + + + + + + + + + +
t1t2t3t4t5t6
c1c2c3c4c5c6
', + 'var2' => $faker->words(1, true) + ]; + $dbEngine = 'mysql'; // This only affects the way to escape the variables with "@@" prefix + $applyEntities = true; // Is true because the string will b used in a output document or a email template + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithVariablesToReplace, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp('//', $stringToCheck); + $this->assertRegExp('//', $stringToCheck); + $this->assertRegExp('/
/', $stringToCheck); + $this->assertRegExp('//', $stringToCheck); + } + + /** + * This checks that strings with tag
should not be replaced, because is a valid tag + * @test + */ + public function it_should_no_replace_tag_br() + { + // Initializing variables to use + $stringWithTagBr = nl2br("prospection auprès d'entreprises de CA < 10 M euros +test +a +&a +\"a +'a +¢a +£a +¥a +€a +©a +®a +test"); + $valuesToReplace = []; + $dbEngine = 'mysql'; // This only affects the way to escape the variables with "@@" prefix + $applyEntities = true; // Is true because the string will b used in a output document or a email template + + // Replace variables in the string + $stringToCheck = G::replaceDataField($stringWithTagBr, $valuesToReplace, $dbEngine, $applyEntities); + + // Assertions + $this->assertRegExp("/
/", $stringToCheck); + } +} diff --git a/tests/unit/workflow/engine/classes/PmDynaformTest.php b/tests/unit/workflow/engine/classes/PmDynaformTest.php new file mode 100644 index 000000000..d6c033209 --- /dev/null +++ b/tests/unit/workflow/engine/classes/PmDynaformTest.php @@ -0,0 +1,535 @@ +createArrayDynaform(); + + $process = factory(Process::class, 1)->create(); + + $dynaform = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 6, + 'DYN_UID' => $arrayForm['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm) + ]); + + $pmDynaform = new PmDynaform(); + $result = $pmDynaform->getDynaform(); + + $this->assertEquals(null, $result); + } + + /** + * Check if the getDynaform() method returning null if parameters is empty. + * @covers PmDynaform::getDynaform + * @test + */ + public function it_should_return_null_if_parameters_is_empty() + { + $arrayForm = $this->createArrayDynaform(); + + $process = factory(Process::class, 1)->create(); + + $dynaform = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 5, + 'DYN_UID' => $arrayForm['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm) + ]); + + $pmDynaform = new PmDynaform([]); + $result = $pmDynaform->getDynaform(); + + $this->assertEquals(null, $result); + } + + /** + * Check if the getDynaform() method returning null if current dynaform not exist. + * @covers PmDynaform::getDynaform + * @test + */ + public function it_should_return_null_if_current_dynaform_not_exist() + { + $arrayForm = $this->createArrayDynaform(); + + $process = factory(Process::class, 1)->create(); + + $dynaform = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 5, + 'DYN_UID' => $arrayForm['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm) + ]); + + $pmDynaform = new PmDynaform(['CURRENT_DYNAFORM' => G::generateUniqueID()]); + $result = $pmDynaform->getDynaform(); + + $this->assertEquals(null, $result); + } + + /** + * Check if the getDynaform() method returning null if parameters is not empty. + * @covers PmDynaform::getDynaform + * @test + */ + public function it_should_return_null_if_parameters_is_not_empty() + { + $arrayForm = $this->createArrayDynaform(); + + $process = factory(Process::class, 1)->create(); + + $dynaform = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 5, + 'DYN_UID' => $arrayForm['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm) + ]); + + $pmDynaform = new PmDynaform(["APP_DATA" => []]); + $result = $pmDynaform->getDynaform(); + + $this->assertEquals(null, $result); + } + + /** + * Check if the getDynaform() method returning null if parameter is a string. + * @covers PmDynaform::getDynaform + * @test + */ + public function it_should_return_null_if_parameter_is_a_string() + { + $arrayForm = $this->createArrayDynaform(); + + $process = factory(Process::class, 1)->create(); + + $dynaform = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 5, + 'DYN_UID' => $arrayForm['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm) + ]); + + $pmDynaform = new PmDynaform(""); + + $result = $pmDynaform->getDynaform(); + + $this->assertEquals(null, $result); + } + + /** + * Check if the getDynaform() method returning null if parameter is a integer. + * @covers PmDynaform::getDynaform + * @test + */ + public function it_should_return_null_if_parameter_is_a_integer() + { + $arrayForm = $this->createArrayDynaform(); + + $process = factory(Process::class, 1)->create(); + + $dynaform = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 5, + 'DYN_UID' => $arrayForm['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm) + ]); + + $pmDynaform = new PmDynaform(1); + + $result = $pmDynaform->getDynaform(); + + $this->assertEquals(null, $result); + } + + /** + * Check if the getDynaform() method returning record property. + * @covers PmDynaform::getDynaform + * @test + */ + public function it_should_return_record_property_if_record_is_not_null() + { + $arrayForm = $this->createArrayDynaform(); + + $process = factory(Process::class, 1)->create(); + + $dynaform = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 4, + 'DYN_UID' => $arrayForm['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm) + ]); + $expected = (array) $dynaform->first()->toArray(); + unset($expected['id']); //This is removed because is aggregate from factory. + //first execution in constructor + $pmDynaform = new PmDynaform(['CURRENT_DYNAFORM' => $arrayForm['items'][0]['id']]); + //second execution + $pmDynaform->getDynaform(); + //third execution + $pmDynaform->getDynaform(); + + $this->assertEquals($expected, $pmDynaform->record); + } + + /** + * Check if the getDynaform() method setting langs property in null if current dynaform not exist. + * @covers PmDynaform::getDynaform + * @test + */ + public function it_should_return_langs_property_in_null_if_current_dynaform_not_exist() + { + $arrayForm = $this->createArrayDynaform(); + + $process = factory(Process::class, 1)->create(); + + $dynaform = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 6, + 'DYN_UID' => $arrayForm['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm) + ]); + + $pmDynaform = new PmDynaform(['CURRENT_DYNAFORM' => G::generateUniqueID()]); + $pmDynaform->getDynaform(); + + $this->assertEquals(null, $pmDynaform->langs); + } + + /** + * Check if the getDynaform() method returning null if dynaform not exist in the process. + * @covers PmDynaform::getDynaform + * @test + */ + public function it_should_return_null_if_dynaform_not_exist_in_the_process() + { + $arrayForm = $this->createArrayDynaform(); + + $process = factory(Process::class, 1)->create(); + + $dynaform = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 5, + 'DYN_UID' => $arrayForm['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm) + ]); + + $pmDynaform = new PmDynaform(['CURRENT_DYNAFORM' => G::generateUniqueID()]); + $pmDynaform->getDynaform(); + + $this->assertEquals(null, $pmDynaform->record); + } + + /** + * Check if the getDynaform() method returning fields. + * @covers PmDynaform::getDynaform + * @test + */ + public function it_should_return_a_dynaform_in_array_format() + { + $arrayForm = $this->createArrayDynaform(); + + $process = factory(Process::class, 1)->create(); + + $dynaform = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 3, + 'DYN_UID' => $arrayForm['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm) + ]); + $expected = (array) $dynaform->first()->toArray(); + unset($expected['id']); //This is removed because is aggregate from factory. + + $pmDynaform = new PmDynaform(['CURRENT_DYNAFORM' => $arrayForm['items'][0]['id']]); + $result = $pmDynaform->getDynaform(); + $this->assertEquals($expected, $result); + } + + /** + * Check if the getDynaforms() method returning null when not exist dynaform. + * @covers PmDynaform::getDynaforms + * @test + */ + public function it_should_return_null_when_not_exist_dynaform() + { + $process = factory(Process::class, 1)->create(); + + $arrayForm = $this->createArrayDynaform(); + $dynaform = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 7, + 'DYN_UID' => $arrayForm['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm) + ]); + + $pmDynaform = new PmDynaform(); + $result = $pmDynaform->getDynaforms(['CURRENT_DYNAFORM' => G::generateUniqueID()]); + + $this->assertEquals(null, $result); + } + + /** + * Check if the getDynaforms() method returning null when record is null. + * @covers PmDynaform::getDynaforms + * @test + */ + public function it_should_return_null_when_record_is_null() + { + $pmDynaform = new PmDynaform(); + $pmDynaform->getDynaforms(); + + $this->assertEquals(null, $pmDynaform->record); + } + + /** + * Check if the getDynaforms() method returning record property. + * @covers PmDynaform::getDynaforms + * @test + */ + public function it_should_return_array_dynaforms_except_current_dynaform_in_second_execution() + { + $process = factory(Process::class, 1)->create(); + + $arrayForm = $this->createArrayDynaform(); + $dynaform = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 7, + 'DYN_UID' => $arrayForm['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm) + ]); + + $arrayForm2 = $this->createArrayDynaform(); + $dynaform2 = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 9, + 'DYN_UID' => $arrayForm2['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm2) + ]); + + $expected = (array) $dynaform2->first()->toArray(); + unset($expected['id']); //This is removed because is aggregate from factory. + + $pmDynaform = new PmDynaform(['CURRENT_DYNAFORM' => $arrayForm['items'][0]['id']]); + $pmDynaform->getDynaforms(); + + $this->assertEquals([$expected], $pmDynaform->records); + } + + /** + * Check if the getDynaforms() method returning arrays dynaforms except current dynaform. + * @covers PmDynaform::getDynaforms + * @test + */ + public function it_should_return_array_dynaforms_except_current_dynaform() + { + $process = factory(Process::class, 1)->create(); + + $arrayForm = $this->createArrayDynaform(); + $dynaform = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 7, + 'DYN_UID' => $arrayForm['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm) + ]); + + $arrayForm2 = $this->createArrayDynaform(); + $dynaform2 = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 9, + 'DYN_UID' => $arrayForm2['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm2) + ]); + + $expected = (array) $dynaform2->first()->toArray(); + unset($expected['id']); //This is removed because is aggregate from factory. + + $pmDynaform = new PmDynaform(['CURRENT_DYNAFORM' => $arrayForm['items'][0]['id']]); + $result = $pmDynaform->getDynaforms(); + + $this->assertEquals([$expected], $result); + } + + /** + * Check if the isUsed() method is returning false when not exist data related to process id. + * @covers PmDynaform::isUsed + * @test + */ + public function it_should_return_false_when_not_exist_data_related_to_id_process() + { + $processId = G::generateUniqueID(); + + $pmDynaform = new PmDynaform(); + $result = $pmDynaform->isUsed($processId, 'var1'); + + $this->assertEquals(false, $result); + } + + /** + * Check if the isUsed() method is returning the ID of the dynaform in case + * the variable is part of the dynaform. + * @covers PmDynaform::isUsed + * @test + */ + public function it_should_return_id_of_dynaform_when_is_used_variable() + { + $arrayForm = $this->createArrayDynaform(); + + $process = factory(Process::class, 1)->create(); + + $dynaform = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 1, + 'DYN_UID' => $arrayForm['items'][0]['id'], + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm) + ]); + + $pmDynaform = new PmDynaform(); + $result = $pmDynaform->isUsed($process[0]->PRO_UID, $arrayForm['items'][0]['variables'][0]); + + $this->assertEquals($dynaform[0]->DYN_UID, $result); + } + + /** + * Check if the isUsed() method is returning false in case the variable is + * not part of the dynaform. + * @covers PmDynaform::isUsed + * @test + */ + public function it_should_return_false_when_not_used_variable() + { + $arrayVariable = $this->createArrayVariable('var10'); + + $arrayForm = $this->createArrayDynaform(); + + $process = factory(Process::class, 1)->create(); + + $dynaform = factory(Dynaform::class, 1)->create([ + 'DYN_ID' => 2, + 'PRO_UID' => $process[0]->PRO_UID, + 'DYN_CONTENT' => G::json_encode($arrayForm) + ]); + + $pmDynaform = new PmDynaform(); + $result = $pmDynaform->isUsed($process[0]->PRO_UID, $arrayVariable); + + $this->assertEquals(false, $result); + } + + /** + * Return an object that represents the structure of a process variable. + * @return array + */ + private function createArrayVariable($varName) + { + return [ + "var_uid" => G::generateUniqueID(), + "prj_uid" => G::generateUniqueID(), + "var_name" => $varName, + "var_field_type" => "string", + "var_field_size" => 10, + "var_label" => "string", + "var_dbconnection" => "workflow", + "var_dbconnection_label" => "PM Database", + "var_sql" => "", + "var_null" => 0, + "var_default" => "", + "var_accepted_values" => "[]", + "inp_doc_uid" => "" + ]; + } + + /** + * Returns an object that represents the structure of a control. + * @return array + */ + private function createArrayControl($varUid, $varName) + { + return [ + "type" => "textarea", + "variable" => $varName, + "var_uid" => $varUid, + "dataType" => "string", + "protectedValue" => false, + "id" => "textareaVar001", + "name" => "textareaVar001", + "label" => "textarea_1", + "defaultValue" => "", + "placeholder" => "", + "hint" => "", + "required" => false, + "requiredFieldErrorMessage" => "", + "validate" => "", + "validateMessage" => "", + "mode" => "parent", + "dbConnection" => "workflow", + "dbConnectionLabel" => "PM Database", + "sql" => "", + "rows" => "5", + "var_name" => "textareaVar001", + "colSpan" => 12 + ]; + } + + /** + * Returns an object that represents the structure of a dynaform. + * @return array + */ + private function createArrayDynaform() + { + $var1 = $this->createArrayVariable('var1'); + $control1 = $this->createArrayControl($var1['var_uid'], $var1['var_name']); + + $var2 = $this->createArrayVariable('var2'); + $control2 = $this->createArrayControl($var2['var_uid'], $var2['var_name']); + + return [ + "name" => "subform", + "description" => "", + "items" => [ + [ + "type" => "form", + "variable" => "", + "var_uid" => "", + "dataType" => "", + "id" => G::generateUniqueID(), + "name" => "subform", + "description" => "", + "mode" => "edit", + "script" => "", + "language" => "en", + "externalLibs" => "", + "printable" => false, + "items" => [ + [$control1], + [$control2] + ], + "variables" => [ + $var1, + $var2 + ] + ] + ] + ]; + } +} diff --git a/tests/unit/workflow/engine/src/ProcessMaker/Model/DelegationTest.php b/tests/unit/workflow/engine/src/ProcessMaker/Model/DelegationTest.php new file mode 100644 index 000000000..2159454c8 --- /dev/null +++ b/tests/unit/workflow/engine/src/ProcessMaker/Model/DelegationTest.php @@ -0,0 +1,1046 @@ +create(); + factory(Process::class, 10)->create(); + factory(Delegation::class, 51)->create(); + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25); + $this->assertCount(1, $results['data']); + } + + /** + * This checks to make sure pagination is working properly + * @test + */ + public function it_should_return_pages_of_data_unassigned() + { + factory(User::class, 100)->create(); + factory(Process::class, 10)->create(); + + factory(Delegation::class, 50)->create(); + factory(Delegation::class, 1)->create([ + 'USR_ID' => 0 // A self service delegation + ]); + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25); + $this->assertCount(1, $results['data']); + } + + /** + * This checks to make sure filter by process is working properly + * @test + */ + public function it_should_return_process_of_data() + { + factory(User::class, 100)->create(); + $process = factory(Process::class, 1)->create([ + 'PRO_ID' => 1 + ]); + factory(Delegation::class, 51)->create([ + 'PRO_ID' => $process[0]->id + ]); + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25, null, $process[0]->id); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25, null, $process[0]->id); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25, null, $process[0]->id); + $this->assertCount(1, $results['data']); + } + + /** + * This checks to make sure filter by status is working properly + * Review status filter by a specific status, such as Draft + * @test + */ + public function it_should_return_status_draft_of_data() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001, + 'APP_STATUS_ID' => 1, + 'APP_STATUS' => 'DRAFT' + ]); + factory(Delegation::class, 51)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Review the filter by status DRAFT + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(1, $results['data']); + } + + /** + * This checks to make sure filter by status is working properly + * Review status filter by a specific status, such as To Do + * @test + */ + public function it_should_return_status_todo_of_data() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001, + 'APP_STATUS_ID' => 2, + 'APP_STATUS' => 'TO_DO' + ]); + factory(Delegation::class, 51)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Review the filter by status TO_DO + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(1, $results['data']); + } + + /** + * This checks to make sure filter by status is working properly + * Review status filter by a specific status, such as Completed + * @test + */ + public function it_should_return_status_completed_of_data() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001, + 'APP_STATUS_ID' => 3, + 'APP_STATUS' => 'COMPLETED', + ]); + + factory(Delegation::class, 51)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'DEL_LAST_INDEX' => 1 + ]); + // Review the filter by status COMPLETED + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(1, $results['data']); + } + + /** + * This checks to make sure filter by status is working properly + * Review status filter by a specific status, such as Cancelled + * @test + */ + public function it_should_return_status_cancelled_of_data() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001, + 'APP_STATUS_ID' => 4, + 'APP_STATUS' => 'CANCELLED' + ]); + + factory(Delegation::class, 51)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'DEL_LAST_INDEX' => 1 + ]); + // Review the filter by status CANCELLED + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25, null, null, $application[0]->APP_STATUS_ID); + $this->assertCount(1, $results['data']); + } + + /** + * This ensures searching for a valid user works + * @test + */ + public function it_should_return_one_result_for_specified_user() + { + factory(User::class, 100)->create(); + factory(Process::class, 10)->create(); + // Create our unique user, with a unique username + $user = factory(User::class)->create([ + 'USR_USERNAME' => 'testcaseuser' + ]); + // Create a new delegation, but for this specific user + factory(Delegation::class)->create([ + 'USR_UID' => $user->USR_UID, + 'USR_ID' => $user->id + ]); + // Now fetch results, and assume delegation count is 1 and the user points to our user + $results = Delegation::search($user->id); + $this->assertCount(1, $results['data']); + $this->assertEquals('testcaseuser', $results['data'][0]['USRCR_USR_USERNAME']); + } + + /** + * This ensures searching by case number and review the page + * @test + */ + public function it_should_search_by_case_id_and_pages_of_data() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2010 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2011 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2012 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2013 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2014 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2015 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Get first page, the major case id + $results = Delegation::search(null, 0, 10, 1, null, null, 'DESC', + 'APP_NUMBER', null, null, null, 'APP_NUMBER'); + $this->assertCount(7, $results['data']); + $this->assertEquals(2015, $results['data'][0]['APP_NUMBER']); + // Get first page, the minor case id + $results = Delegation::search(null, 0, 10, 1, null, null, 'ASC', + 'APP_NUMBER', null, null, null, 'APP_NUMBER'); + $this->assertCount(7, $results['data']); + $this->assertEquals(2001, $results['data'][0]['APP_NUMBER']); + //Check the pagination + $results = Delegation::search(null, 0, 5, 1, null, null, 'DESC', + 'APP_NUMBER', null, null, null, 'APP_NUMBER'); + $this->assertCount(5, $results['data']); + $results = Delegation::search(null, 5, 2, 1, null, null, 'DESC', + 'APP_NUMBER', null, null, null, 'APP_NUMBER'); + $this->assertCount(2, $results['data']); + } + + /** + * This ensures searching by case title and review the page + * case title contain the case number, ex: APP_TITLE = 'Request # @=APP_NUMBER' + * @test + */ + public function it_should_search_by_case_title_and_pages_of_data_app_number_matches_case_title() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 3001, + 'APP_TITLE' => 'Request # 3001' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 3010, + 'APP_TITLE' => 'Request # 3010' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 3011, + 'APP_TITLE' => 'Request # 3011' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 3012, + 'APP_TITLE' => 'Request # 3012' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 3013, + 'APP_TITLE' => 'Request # 3013' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_TITLE' => 3014, + 'APP_TITLE' => 'Request # 3014' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + + // Get first page, the major case id + $results = Delegation::search(null, 0, 10, '1', null, null, 'DESC', + 'APP_NUMBER', null, null, null, 'APP_TITLE'); + $this->assertCount(6, $results['data']); + $this->assertEquals('Request # 3014', $results['data'][0]['APP_TITLE']); + + // Get first page, the minor case id + $results = Delegation::search(null, 0, 10, '1', null, null, 'ASC', + 'APP_NUMBER', null, null, null, 'APP_TITLE'); + $this->assertCount(6, $results['data']); + $this->assertEquals(3001, $results['data'][0]['APP_NUMBER']); + $this->assertEquals('Request # 3001', $results['data'][0]['APP_TITLE']); + //Check the pagination + $results = Delegation::search(null, 0, 5, '1', null, null, 'ASC', + 'APP_NUMBER', null, null, null, 'APP_TITLE'); + $this->assertCount(5, $results['data']); + $results = Delegation::search(null, 5, 2, '1', null, null, 'ASC', + 'APP_NUMBER', null, null, null, 'APP_TITLE'); + $this->assertCount(1, $results['data']); + } + + /** + * This ensures searching by task title and review the page + * @test + */ + public function it_should_search_by_task_title_and_pages_of_data() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $task = factory(Task::class, 1)->create([ + 'TAS_ID' => 1, + 'TAS_TITLE' => 'Request task' + ]); + factory(Delegation::class, 5)->create([ + 'TAS_ID' => $task[0]->TAS_ID + ]); + $task = factory(Task::class, 1)->create([ + 'TAS_ID' => 2, + 'TAS_TITLE' => 'Account task' + ]); + factory(Delegation::class, 5)->create([ + 'TAS_ID' => $task[0]->TAS_ID + ]); + // Get first page, the order taskTitle + $results = Delegation::search(null, 0, 6, 'task', null, null, 'ASC', + 'TAS_TITLE', null, null, null, 'TAS_TITLE'); + $this->assertCount(6, $results['data']); + $this->assertEquals('Account task', $results['data'][0]['APP_TAS_TITLE']); + $results = Delegation::search(null, 6, 6, 'task', null, null, 'ASC', + 'TAS_TITLE', null, null, null, 'TAS_TITLE'); + $this->assertEquals('Request task', $results['data'][0]['APP_TAS_TITLE']); + + // Get first page, the order taskTitle + $results = Delegation::search(null, 0, 6, 'task', null, null, 'DESC', + 'TAS_TITLE', null, null, null, 'TAS_TITLE'); + $this->assertCount(6, $results['data']); + $this->assertEquals('Request task', $results['data'][0]['APP_TAS_TITLE']); + $results = Delegation::search(null, 6, 6, 'task', null, null, 'DESC', + 'TAS_TITLE', null, null, null, 'TAS_TITLE'); + $this->assertEquals('Account task', $results['data'][0]['APP_TAS_TITLE']); + //Check the pagination + $results = Delegation::search(null, 0, 6, 'task', null, null, 'DESC', + 'TAS_TITLE', null, null, null, 'TAS_TITLE'); + $this->assertCount(6, $results['data']); + $results = Delegation::search(null, 6, 6, 'task', null, null, 'DESC', + 'TAS_TITLE', null, null, null, 'TAS_TITLE'); + $this->assertCount(4, $results['data']); + } + + /** + * This ensures searching by case title and review the page + * case title does not match with case number (hertland use case) + * @test + */ + public function it_should_search_by_case_title_and_pages_of_data_app_number_no_matches_case_title() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001, + 'APP_TITLE' => 'Request from Abigail check nro 25001' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2010, + 'APP_TITLE' => 'Request from Abigail check nro 12' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2011, + 'APP_TITLE' => 'Request from Abigail check nro 1000' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2012, + 'APP_TITLE' => 'Request from Abigail check nro 11000' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2013, + 'APP_TITLE' => 'Request from Abigail check nro 12000' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_TITLE' => 2014, + 'APP_TITLE' => 'Request from Abigail check nro 111' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Get first page, the major case title + $results = Delegation::search(null, 0, 10, '1', null, null, 'ASC', + 'APP_NUMBER', null, null, null, 'APP_TITLE'); + $this->assertCount(6, $results['data']); + $this->assertEquals(2001, $results['data'][0]['APP_NUMBER']); + $this->assertEquals('Request from Abigail check nro 25001', $results['data'][0]['APP_TITLE']); + + //Check the pagination + $results = Delegation::search(null, 0, 5, '1', null, null, 'ASC', + 'APP_NUMBER', null, null, null, 'APP_TITLE'); + $this->assertCount(5, $results['data']); + $results = Delegation::search(null, 5, 2, '1', null, null, 'ASC', + 'APP_NUMBER', null, null, null, 'APP_TITLE'); + $this->assertCount(1, $results['data']); + } + + /** + * This ensures ordering ascending and descending works by case number APP_NUMBER + * @test + */ + public function it_should_sort_by_case_id() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 30002 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Get first page, the minor case id + $results = Delegation::search(null, 0, 25, null, null, null, 'ASC', 'APP_NUMBER'); + $this->assertCount(2, $results['data']); + $this->assertEquals(2001, $results['data'][0]['APP_NUMBER']); + $this->assertEquals(30002, $results['data'][1]['APP_NUMBER']); + // Get first page, the major case id + $results = Delegation::search(null, 0, 25, null, null, null, 'DESC', 'APP_NUMBER'); + $this->assertCount(2, $results['data']); + $this->assertEquals(30002, $results['data'][0]['APP_NUMBER']); + $this->assertEquals(2001, $results['data'][1]['APP_NUMBER']); + } + + /** + * This ensures ordering ascending and descending works by case title APP_TITLE + * @test + */ + public function it_should_sort_by_case_title() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001, + 'APP_TITLE' => 'Request by Thomas' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 30002, + 'APP_TITLE' => 'Request by Ariel' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Get first page, the minor case id + $results = Delegation::search(null, 0, 25, null, null, null, 'ASC', 'APP_TITLE'); + $this->assertCount(2, $results['data']); + $this->assertEquals('Request by Ariel', $results['data'][0]['APP_TITLE']); + $this->assertEquals('Request by Thomas', $results['data'][1]['APP_TITLE']); + // Get first page, the major case id + $results = Delegation::search(null, 0, 25, null, null, null, 'DESC', 'APP_TITLE'); + $this->assertCount(2, $results['data']); + $this->assertEquals('Request by Thomas', $results['data'][0]['APP_TITLE']); + $this->assertEquals('Request by Ariel', $results['data'][1]['APP_TITLE']); + } + + /** + * This ensures ordering ascending and descending works by case title APP_PRO_TITLE + * @test + */ + public function it_should_sort_by_process() + { + factory(User::class, 100)->create(); + $process = factory(Process::class, 1)->create([ + 'PRO_ID' => 2, + 'PRO_TITLE' => 'Egypt Supplier Payment Proposal' + ]); + factory(Delegation::class, 1)->create([ + 'PRO_ID' => $process[0]->id + ]); + $process = factory(Process::class, 1)->create([ + 'PRO_ID' => 1, + 'PRO_TITLE' => 'China Supplier Payment Proposal' + ]); + factory(Delegation::class, 1)->create([ + 'PRO_ID' => $process[0]->id + ]); + $process = factory(Process::class, 1)->create([ + 'PRO_ID' => 3, + 'PRO_TITLE' => 'Russia Supplier Payment Proposal' + ]); + factory(Delegation::class, 1)->create([ + 'PRO_ID' => $process[0]->id + ]); + // Get first page, all process ordering ascending + $results = Delegation::search(null, 0, 3, null, null, null, 'ASC', 'APP_PRO_TITLE'); + $this->assertCount(3, $results['data']); + $this->assertEquals('China Supplier Payment Proposal', $results['data'][0]['APP_PRO_TITLE']); + $this->assertEquals('Egypt Supplier Payment Proposal', $results['data'][1]['APP_PRO_TITLE']); + $this->assertEquals('Russia Supplier Payment Proposal', $results['data'][2]['APP_PRO_TITLE']); + // Get first page, all process ordering descending + $results = Delegation::search(null, 0, 3, null, null, null, 'DESC', 'APP_PRO_TITLE'); + $this->assertCount(3, $results['data']); + $this->assertEquals('Russia Supplier Payment Proposal', $results['data'][0]['APP_PRO_TITLE']); + $this->assertEquals('Egypt Supplier Payment Proposal', $results['data'][1]['APP_PRO_TITLE']); + $this->assertEquals('China Supplier Payment Proposal', $results['data'][2]['APP_PRO_TITLE']); + } + + /** + * This ensures ordering ascending and descending works by task title APP_TAS_TITLE + * @test + */ + public function it_should_sort_by_task_title() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + + $task = factory(Task::class, 1)->create([ + 'TAS_ID' => 1000, + 'TAS_TITLE' => 'Initiate Request' + ]); + factory(Delegation::class, 1)->create([ + 'TAS_ID' => $task[0]->TAS_ID + ]); + + $task = factory(Task::class, 1)->create([ + 'TAS_ID' => 4000, + 'TAS_TITLE' => 'Waiting for AP Manager Validation' + ]); + factory(Delegation::class, 1)->create([ + 'TAS_ID' => $task[0]->TAS_ID + ]); + + $results = Delegation::search(null, 0, 25, null, null, null, 'ASC', 'APP_TAS_TITLE'); + $this->assertCount(2, $results['data']); + $this->assertEquals('Initiate Request', $results['data'][0]['APP_TAS_TITLE']); + $this->assertEquals('Waiting for AP Manager Validation', $results['data'][1]['APP_TAS_TITLE']); + + $results = Delegation::search(null, 0, 25, null, null, null, 'DESC', 'APP_TAS_TITLE'); + $this->assertCount(2, $results['data']); + $this->assertEquals('Waiting for AP Manager Validation', $results['data'][0]['APP_TAS_TITLE']); + $this->assertEquals('Initiate Request', $results['data'][1]['APP_TAS_TITLE']); + } + + /** + * This ensures ordering ascending and descending works by current user + * @test + */ + public function it_should_sort_by_user() + { + factory(User::class, 100)->create(); + factory(Process::class, 10)->create(); + // Create our unique user, with a unique username + $user = factory(User::class)->create([ + 'USR_USERNAME' => 'gary', + 'USR_LASTNAME' => 'Gary', + 'USR_FIRSTNAME' => 'Bailey', + ]); + // Create a new delegation, but for this specific user + factory(Delegation::class)->create([ + 'USR_UID' => $user->USR_UID, + 'USR_ID' => $user->id + ]); + $user = factory(User::class)->create([ + 'USR_USERNAME' => 'paul', + 'USR_LASTNAME' => 'Paul', + 'USR_FIRSTNAME' => 'Griffis', + ]); + // Create a new delegation, but for this specific user + factory(Delegation::class)->create([ + 'USR_UID' => $user->USR_UID, + 'USR_ID' => $user->id + ]); + // Now fetch results, and assume delegation count is 2 and the ordering ascending return Gary + $results = Delegation::search(null, 0, 25, null, null, null, 'ASC', 'APP_CURRENT_USER'); + $this->assertCount(2, $results['data']); + $this->assertEquals('Gary Bailey', $results['data'][0]['APP_CURRENT_USER']); + + // Now fetch results, and assume delegation count is 2 and the ordering descending return Gary + $results = Delegation::search(null, 0, 25, null, null, null, 'DESC', 'APP_CURRENT_USER'); + $this->assertCount(2, $results['data']); + $this->assertEquals('Paul Griffis', $results['data'][0]['APP_CURRENT_USER']); + } + + /** + * This ensures ordering ordering ascending and descending works by last modified APP_UPDATE_DATE + * @test + */ + public function it_should_sort_by_last_modified() + { + factory(User::class,100)->create(); + factory(Process::class,1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_UPDATE_DATE' => '2019-01-02 00:00:00' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_UPDATE_DATE' => '2019-01-03 00:00:00' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_UPDATE_DATE' => '2019-01-04 00:00:00' + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Get first page, the minor last modified + $results = Delegation::search(null, 0, 1, null, null, null, 'ASC', 'APP_UPDATE_DATE'); + $this->assertCount(1, $results['data']); + $this->assertEquals('2019-01-02 00:00:00', $results['data'][0]['APP_UPDATE_DATE']); + + $results = Delegation::search(null, 1, 1, null, null, null, 'ASC', 'APP_UPDATE_DATE'); + $this->assertCount(1, $results['data']); + $this->assertEquals('2019-01-03 00:00:00', $results['data'][0]['APP_UPDATE_DATE']); + + $results = Delegation::search(null, 2, 1, null, null, null, 'ASC', 'APP_UPDATE_DATE'); + $this->assertCount(1, $results['data']); + $this->assertEquals('2019-01-04 00:00:00', $results['data'][0]['APP_UPDATE_DATE']); + + $results = Delegation::search(null, 0, 1, null, null, null, 'DESC', 'APP_UPDATE_DATE'); + $this->assertCount(1, $results['data']); + $this->assertEquals('2019-01-04 00:00:00', $results['data'][0]['APP_UPDATE_DATE']); + + $results = Delegation::search(null, 1, 1, null, null, null, 'DESC', 'APP_UPDATE_DATE'); + $this->assertCount(1, $results['data']); + $this->assertEquals('2019-01-03 00:00:00', $results['data'][0]['APP_UPDATE_DATE']); + + $results = Delegation::search(null, 2, 1, null, null, null, 'DESC', 'APP_UPDATE_DATE'); + $this->assertCount(1, $results['data']); + $this->assertEquals('2019-01-02 00:00:00', $results['data'][0]['APP_UPDATE_DATE']); + } + + /** + * This ensures ordering ascending and descending works by due date DEL_TASK_DUE_DATE + * @test + */ + public function it_should_sort_by_due_date() + { + factory(User::class,100)->create(); + factory(Process::class,1)->create(); + factory(Delegation::class, 10)->create([ + 'DEL_TASK_DUE_DATE' => '2019-01-02 00:00:00' + ]); + factory(Delegation::class, 10)->create([ + 'DEL_TASK_DUE_DATE' => '2019-01-03 00:00:00' + ]); + factory(Delegation::class, 9)->create([ + 'DEL_TASK_DUE_DATE' => '2019-01-04 00:00:00' + ]); + // Get first page, the minor last modified + $results = Delegation::search(null, 0, 10, null, null, null, 'ASC', 'DEL_TASK_DUE_DATE'); + $this->assertCount(10, $results['data']); + $this->assertEquals('2019-01-02 00:00:00', $results['data'][0]['DEL_TASK_DUE_DATE']); + + $results = Delegation::search(null, 10, 10, null, null, null, 'ASC', 'DEL_TASK_DUE_DATE'); + $this->assertCount(10, $results['data']); + $this->assertEquals('2019-01-03 00:00:00', $results['data'][0]['DEL_TASK_DUE_DATE']); + + $results = Delegation::search(null, 20, 10, null, null, null, 'ASC', 'DEL_TASK_DUE_DATE'); + $this->assertCount(9, $results['data']); + $this->assertEquals('2019-01-04 00:00:00', $results['data'][0]['DEL_TASK_DUE_DATE']); + + $results = Delegation::search(null, 0, 10, null, null, null, 'DESC', 'DEL_TASK_DUE_DATE'); + $this->assertCount(10, $results['data']); + $this->assertEquals('2019-01-04 00:00:00', $results['data'][0]['DEL_TASK_DUE_DATE']); + + $results = Delegation::search(null, 10, 10, null, null, null, 'DESC', 'DEL_TASK_DUE_DATE'); + $this->assertCount(10, $results['data']); + $this->assertEquals('2019-01-03 00:00:00', $results['data'][0]['DEL_TASK_DUE_DATE']); + + $results = Delegation::search(null, 20, 10, null, null, null, 'DESC', 'DEL_TASK_DUE_DATE'); + $this->assertCount(9, $results['data']); + $this->assertEquals('2019-01-02 00:00:00', $results['data'][0]['DEL_TASK_DUE_DATE']); + } + + /** + * This ensures ordering ascending and descending works by status APP_STATUS + * @test + */ + public function it_should_sort_by_status() + { + factory(User::class,100)->create(); + factory(Process::class,1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_STATUS' => 'DRAFT' + ]); + factory(Delegation::class, 25)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_STATUS' => 'TO_DO' + ]); + factory(Delegation::class, 25)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_STATUS' => 'COMPLETED' + ]); + factory(Delegation::class, 25)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + $application = factory(Application::class, 1)->create([ + 'APP_STATUS' => 'CANCELLED' + ]); + factory(Delegation::class, 25)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + + // Get first page, the minor status label + $results = Delegation::search(null, 0, 25, null, null, null, 'ASC', 'APP_STATUS'); + $this->assertEquals('CANCELLED', $results['data'][0]['APP_STATUS']); + $results = Delegation::search(null, 25, 25, null, null, null, 'ASC', 'APP_STATUS'); + $this->assertEquals('COMPLETED', $results['data'][0]['APP_STATUS']); + $results = Delegation::search(null, 50, 25, null, null, null, 'ASC', 'APP_STATUS'); + $this->assertEquals('DRAFT', $results['data'][0]['APP_STATUS']); + $results = Delegation::search(null, 75, 25, null, null, null, 'ASC', 'APP_STATUS'); + $this->assertEquals('TO_DO', $results['data'][0]['APP_STATUS']); + // Get first page, the major status label + $results = Delegation::search(null, 0, 25, null, null, null, 'DESC', 'APP_STATUS'); + $this->assertEquals('TO_DO', $results['data'][0]['APP_STATUS']); + $results = Delegation::search(null, 25, 25, null, null, null, 'DESC', 'APP_STATUS'); + $this->assertEquals('DRAFT', $results['data'][0]['APP_STATUS']); + $results = Delegation::search(null, 50, 25, null, null, null, 'DESC', 'APP_STATUS'); + $this->assertEquals('COMPLETED', $results['data'][0]['APP_STATUS']); + $results = Delegation::search(null, 75, 25, null, null, null, 'DESC', 'APP_STATUS'); + $this->assertEquals('CANCELLED', $results['data'][0]['APP_STATUS']); + } + + /** + * This checks to make sure filter by category is working properly + * @test + */ + public function it_should_return_data_filtered_by_process_category() + { + factory(User::class, 100)->create(); + // Dummy Processes + factory(ProcessCategory::class, 4)->create(); + factory(Process::class, 4)->create([ + 'PRO_CATEGORY' => ProcessCategory::all()->random()->CATEGORY_UID + ]); + // Dummy Delegations + factory(Delegation::class, 100)->create([ + 'PRO_ID' => Process::all()->random()->PRO_ID + ]); + // Process with the category to search + $processCategorySearch = factory(ProcessCategory::class, 1)->create(); + $categoryUid = $processCategorySearch[0]->CATEGORY_UID; + $processSearch = factory(Process::class, 1)->create([ + 'PRO_ID' => 5, + 'PRO_CATEGORY' => $categoryUid + ]); + // Delegations to found + factory(Delegation::class, 51)->create([ + 'PRO_ID' => $processSearch[0]->id + ]); + + // Get first page, which is 25 + $results = Delegation::search(null, 0, 25, null, null, null, null, null, $categoryUid); + $this->assertCount(25, $results['data']); + // Get second page, which is 25 results + $results = Delegation::search(null, 25, 25, null, null, null, null, null, $categoryUid); + $this->assertCount(25, $results['data']); + // Get third page, which is only 1 result + $results = Delegation::search(null, 50, 25, null, null, null, null, null, $categoryUid); + $this->assertCount(1, $results['data']); + } + + /** + * This ensure the result is right when you search between two given dates + * @test + */ + public function it_should_return_right_data_between_two_dates() + { + factory(User::class, 10)->create(); + factory(Process::class, 10)->create(); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-02 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-03 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-04 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-05 00:00:00']); + $results = Delegation::search(null, 0, 25, null, null, null, null, null, null, '2019-01-02 00:00:00', + '2019-01-03 00:00:00'); + $this->assertCount(20, $results['data']); + foreach ($results['data'] as $value) { + $this->assertGreaterThanOrEqual('2019-01-02 00:00:00', $value['DEL_DELEGATE_DATE']); + $this->assertLessThanOrEqual('2019-01-03 00:00:00', $value['DEL_DELEGATE_DATE']); + $this->assertRegExp('(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ', $value['DEL_DELEGATE_DATE']); + } + } + + /** + * This ensure the result is right when you search from a given date + * @test + */ + public function it_should_return_right_data_when_you_send_only_dateFrom_parameter() + { + factory(User::class, 10)->create(); + factory(Process::class, 10)->create(); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-02 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-03 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-04 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-05 00:00:00']); + $results = Delegation::search(null, 0, 50, null, null, null, null, null, null, '2019-01-02 00:00:00', + null); + $this->assertCount(40, $results['data']); + foreach ($results['data'] as $value) { + $this->assertGreaterThanOrEqual('2019-01-02 00:00:00', $value['DEL_DELEGATE_DATE']); + $this->assertRegExp('(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ', $value['DEL_DELEGATE_DATE']); + } + } + + /** + * This ensure the result is right when you search to a given date + * @test + */ + public function it_should_return_right_data_when_you_send_only_dateTo_parameter() + { + factory(User::class, 10)->create(); + factory(Process::class, 10)->create(); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-02 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-03 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-04 00:00:00']); + factory(Delegation::class, 10)->create(['DEL_DELEGATE_DATE' => '2019-01-05 00:00:00']); + $results = Delegation::search(null, 0, 50, null, null, null, null, null, null, null, + '2019-01-04 00:00:00'); + $this->assertCount(30, $results['data']); + foreach ($results['data'] as $value) { + $this->assertLessThanOrEqual('2019-01-04 00:00:00', $value['DEL_DELEGATE_DATE']); + $this->assertRegExp('(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ', $value['DEL_DELEGATE_DATE']); + } + } + + /** + * This ensures return the correct data by sequential + * @test + */ + public function it_should_return_by_sequential_tasks_pages_of_data() + { + factory(User::class, 100)->create(); + // Create a process + $process = factory(Process::class, 1)->create([ + 'PRO_ID' => 1000 + ]); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 5000, + 'APP_TITLE' => 'Request by Thomas', + ]); + // Create task + $task = factory(Task::class, 1)->create([ + 'TAS_TYPE' => 'NORMAL' + ]); + // Create a thread with the user, process and application defined before + factory(Delegation::class)->create([ + 'PRO_ID' => $process[0]->id, + 'TAS_ID' => $task[0]->id, + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'DEL_THREAD_STATUS' => 'CLOSED' + ]); + + // Define a dummy task + $task = factory(Task::class, 1)->create([ + 'TAS_TYPE' => 'INTERMEDIATE-THROW' + ]); + // Create a thread with the dummy task this does not need a user + factory(Delegation::class)->create([ + 'PRO_ID' => $process[0]->id, + 'USR_ID' => 0, + 'TAS_ID' => $task[0]->id, + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Create task + $task = factory(Task::class, 1)->create([ + 'TAS_TYPE' => 'NORMAL' + ]); + // Create a thread with the user, process and application defined before + factory(Delegation::class)->create([ + 'PRO_ID' => $process[0]->id, + 'TAS_ID' => $task[0]->id, + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'DEL_THREAD_STATUS' => 'OPEN' + ]); + // Review if the thread OPEN is showed + $results = Delegation::search(null, 0, 10, null); + $this->assertCount(1, $results['data']); + $this->assertEquals('OPEN', $results['data'][0]['DEL_THREAD_STATUS']); + } + + /** + * This ensures return the correct data by parallel task all threads CLOSED + * @test + */ + public function it_should_return_by_parallel_tasks_threads_closed() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $task = factory(Task::class, 1)->create([ + 'TAS_TITLE' => 'Parallel task 1' + ]); + factory(Delegation::class, 5)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'DEL_THREAD_STATUS' => 'CLOSED' + ]); + $task = factory(Task::class, 1)->create([ + 'TAS_TITLE' => 'Parallel task 2' + ]); + factory(Delegation::class, 5)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'DEL_THREAD_STATUS' => 'CLOSED' + ]); + // Get first page, the order taskTitle + $results = Delegation::search(null, 0, 2, null, null, null, 'ASC', + 'TAS_TITLE', null, null, null, 'TAS_TITLE'); + $this->assertCount(0, $results['data']); + + // Get first page, the order taskTitle + $results = Delegation::search(null, 0, 2, null, null, null, 'DESC', + 'TAS_TITLE', null, null, null, 'TAS_TITLE'); + $this->assertCount(0, $results['data']); + } + + /** + * This ensures return the correct data by parallel task all threads OPEN + * @test + */ + public function it_should_return_by_parallel_tasks_threads_open() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + //Create the threads + factory(Delegation::class, 5)->create([ + 'DEL_THREAD_STATUS' => 'OPEN' + ]); + // Get first page, all the open status + $results = Delegation::search(null, 0, 5, null, null, null); + $this->assertCount(5, $results['data']); + $this->assertEquals('OPEN', $results['data'][0]['DEL_THREAD_STATUS']); + $this->assertEquals('OPEN', $results['data'][4]['DEL_THREAD_STATUS']); + } + + /** + * Review when the status is empty + * @test + */ + public function it_should_return_status_empty() + { + factory(User::class, 100)->create(); + factory(Process::class, 1)->create(); + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001, + 'APP_STATUS' => '' + ]); + factory(Delegation::class, 1)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + // Review the filter by status empty + $results = Delegation::search(null, 0, 25); + $this->assertEquals('', $results['data'][0]['APP_STATUS']); + } +} \ No newline at end of file diff --git a/tests/unit/workflow/engine/src/ProcessMaker/Model/ListUnassignedTest.php b/tests/unit/workflow/engine/src/ProcessMaker/Model/ListUnassignedTest.php new file mode 100644 index 000000000..6574caef7 --- /dev/null +++ b/tests/unit/workflow/engine/src/ProcessMaker/Model/ListUnassignedTest.php @@ -0,0 +1,834 @@ +create(); + //Create user + $user = factory(User::class, 1)->create(); + //Create a task self service + $task = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Assign a user in the task + factory(TaskUser::class, 1)->create([ + 'TAS_UID' => $task[0]->TAS_UID, + 'USR_UID' => $user[0]->USR_UID, + 'TU_RELATION' => 1, //Related to the user + 'TU_TYPE' => 1 + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 15)->create([ + 'TAS_ID' => $task[0]->TAS_ID + ]); + $timeStart = microtime(true); + $result = ListUnassigned::doCount($user[0]->USR_UID); + $timeEnd = microtime(true); + $this->assertEquals(15, $result); + $time = $timeEnd - $timeStart; + error_log('it_should_count_cases_by_user_with_self_service_user_assigned took [15]--->' . $time); + } + + /** + * This checks the counters is working properly in self-service-value-based when the variable has a value related with the USR_UID + * When the value assigned in the variable @@ARRAY_OF_USERS = [USR_UID] + * @covers ListUnassigned::doCount + * @test + */ + public function it_should_count_cases_by_user_with_self_service_value_based_usr_uid() + { + //Create process + $process = factory(Process::class, 1)->create(); + //Create a case + $application = factory(Application::class, 1)->create(); + //Create user + $user = factory(User::class, 1)->create(); + //Create a task self service value based + $task = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '@@ARRAY_OF_USERS', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Create the relation for the value assigned in the TAS_GROUP_VARIABLE + $appSelfValue = factory(AppAssignSelfServiceValue::class, 1)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'DEL_INDEX' => 2, + 'TAS_ID' => $task[0]->TAS_ID + ]); + factory(AppAssignSelfServiceValueGroup::class, 1)->create([ + 'ID' => $appSelfValue[0]->ID, + 'GRP_UID' => $user[0]->USR_UID, + 'ASSIGNEE_ID' => $user[0]->USR_ID, //The usrId or grpId + 'ASSIGNEE_TYPE' => 1 //Related to the user=1 related to the group=2 + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 10)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'DEL_INDEX' => $appSelfValue[0]->DEL_INDEX, + 'TAS_ID' => $task[0]->TAS_ID, + ]); + $timeStart = microtime(true); + $result = ListUnassigned::doCount($user[0]->USR_UID); + $this->assertEquals(10, $result); + $timeEnd = microtime(true); + $time = $timeEnd - $timeStart; + error_log('it_should_count_cases_by_user_with_self_service_value_based_usr_uid took [10]--->' . $time); + } + + /** + * This checks the counters is working properly in self-service and self-service value based + * @covers ListUnassigned::doCount + * @test + */ + public function it_should_count_cases_by_user_with_self_service_mixed_with_self_service_value_based() + { + //Create process + $process = factory(Process::class, 1)->create(); + //Create a case + $application = factory(Application::class, 1)->create(); + //Create user + $user = factory(User::class, 1)->create(); + //Create a task self service + $task = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Assign a user in the task + factory(TaskUser::class, 1)->create([ + 'TAS_UID' => $task[0]->TAS_UID, + 'USR_UID' => $user[0]->USR_UID, + 'TU_RELATION' => 1, //Related to the user + 'TU_TYPE' => 1 + ]); + //Create the register in self service + factory(ListUnassigned::class, 15)->create([ + 'TAS_ID' => $task[0]->TAS_ID + ]); + //Create a task self service value based + $task1 = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '@@ARRAY_OF_USERS', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Create the relation for the value assigned in the TAS_GROUP_VARIABLE + $appSelfValue = factory(AppAssignSelfServiceValue::class, 1)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'DEL_INDEX' => 2, + 'TAS_ID' => $task1[0]->TAS_ID + ]); + factory(AppAssignSelfServiceValueGroup::class, 1)->create([ + 'ID' => $appSelfValue[0]->ID, + 'GRP_UID' => $user[0]->USR_UID, + 'ASSIGNEE_ID' => $user[0]->USR_ID, //The usrId or grpId + 'ASSIGNEE_TYPE' => 1 //Related to the user=1 related to the group=2 + ]); + //Create the register in self service value based + factory(ListUnassigned::class, 10)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'DEL_INDEX' => $appSelfValue[0]->DEL_INDEX, + 'TAS_ID' => $task[0]->TAS_ID, + ]); + + $timeStart = microtime(true); + $result = ListUnassigned::doCount($user[0]->USR_UID); + $timeEnd = microtime(true); + $this->assertEquals(25, $result); + $time = $timeEnd - $timeStart; + error_log('it_should_count_cases_by_user_with_self_service_mixed_with_self_service_value_based took [25]--->' . $time); + } + + /** + * This checks the counters is working properly in self-service group assigned + * @covers ListUnassigned::doCount + * @test + */ + public function it_should_count_cases_by_user_with_self_service_group_assigned() + { + //Create process + $process = factory(Process::class, 1)->create(); + //Create group + $group = factory(Groupwf::class, 1)->create(); + //Create user + $user = factory(User::class, 1)->create(); + //Assign a user in the group + factory(GroupUser::class, 1)->create([ + 'GRP_UID' => $group[0]->GRP_UID, + 'GRP_ID' => $group[0]->GRP_ID, + 'USR_UID' => $user[0]->USR_UID + ]); + //Create a task self service + $task = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Assign a user in the task + factory(TaskUser::class, 1)->create([ + 'TAS_UID' => $task[0]->TAS_UID, + 'USR_UID' => $user[0]->USR_UID, + 'TU_RELATION' => 2, //Related to the group + 'TU_TYPE' => 1 + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 15)->create([ + 'TAS_ID' => $task[0]->TAS_ID + ]); + $timeStart = microtime(true); + $result = ListUnassigned::doCount($user[0]->USR_UID); + $timeEnd = microtime(true); + $this->assertEquals(15, $result); + $time = $timeEnd - $timeStart; + error_log('it_should_count_cases_by_user_with_self_service_group_assigned took [15]--->' . $time); + } + + /** + * This checks the counters is working properly in self-service-value-based when the variable has a value related with the GRP_UID + * When the value assigned in the variable @@ARRAY_OF_USERS = [GRP_UID] + * @covers ListUnassigned::doCount + * @test + */ + public function it_should_count_cases_by_user_with_self_service_value_based_grp_uid() + { + //Create process + $process = factory(Process::class, 1)->create(); + //Create a task self service value based + $task = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '@@ARRAY_OF_USERS', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Create a case + $application = factory(Application::class, 1)->create(); + //Create group + $group = factory(Groupwf::class, 1)->create(); + //Create user + $user = factory(User::class, 1)->create([ + 'USR_USERNAME' => 'gary', + 'USR_LASTNAME' => 'Gary', + 'USR_FIRSTNAME' => 'Bailey', + ]); + //Assign a user in the group + factory(GroupUser::class, 1)->create([ + 'GRP_UID' => $group[0]->GRP_UID, + 'GRP_ID' => $group[0]->GRP_ID, + 'USR_UID' => $user[0]->USR_UID, + ]); + //Create the relation for the value assigned in the TAS_GROUP_VARIABLE + $appSelfValue = factory(AppAssignSelfServiceValue::class, 1)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'APP_UID' => $application[0]->APP_UID, + 'DEL_INDEX' => 2, + 'TAS_ID' => $task[0]->TAS_ID + ]); + factory(AppAssignSelfServiceValueGroup::class, 1)->create([ + 'ID' => $appSelfValue[0]->ID, + 'GRP_UID' => $group[0]->GRP_UID, + 'ASSIGNEE_ID' => $group[0]->GRP_ID, //The usrId or grpId + 'ASSIGNEE_TYPE' => 2 //Related to the user=1 related to the group=2 + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 10)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'DEL_INDEX' => 2, + 'TAS_ID' => $task[0]->TAS_ID, + ]); + $timeStart = microtime(true); + $result = ListUnassigned::doCount($user[0]->USR_UID); + $this->assertEquals(10, $result); + $timeEnd = microtime(true); + $time = $timeEnd - $timeStart; + error_log('it_should_count_cases_by_user_with_self_service_value_based_grp_uid took [10]--->' . $time); + } + + /** + * This checks the counters is working properly in self-service user and group assigned in parallel task + * @covers ListUnassigned::doCount + * @test + */ + public function it_should_count_cases_by_user_with_self_service_user_and_group_assigned_parallel_task() + { + //Create process + $process = factory(Process::class, 1)->create(); + //Create group + $group = factory(Groupwf::class, 1)->create(); + //Create user + $user = factory(User::class, 1)->create(); + //Assign a user in the group + factory(GroupUser::class, 1)->create([ + 'GRP_UID' => $group[0]->GRP_UID, + 'GRP_ID' => $group[0]->GRP_ID, + 'USR_UID' => $user[0]->USR_UID + ]); + //Create a task self service + $task1 = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Assign a user in the task1 + factory(TaskUser::class, 1)->create([ + 'TAS_UID' => $task1[0]->TAS_UID, + 'USR_UID' => $user[0]->USR_UID, + 'TU_RELATION' => 1, //Related to the user + 'TU_TYPE' => 1 + ]); + //Create a task self service + $task2 = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Assign a user in the task2 + factory(TaskUser::class, 1)->create([ + 'TAS_UID' => $task2[0]->TAS_UID, + 'USR_UID' => $user[0]->USR_UID, + 'TU_RELATION' => 1, //Related to the user + 'TU_TYPE' => 1 + ]); + //Create a task self service + $task3 = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Assign a user in the task + factory(TaskUser::class, 1)->create([ + 'TAS_UID' => $task3[0]->TAS_UID, + 'USR_UID' => $group[0]->GRP_UID, + 'TU_RELATION' => 2, //Related to the group + 'TU_TYPE' => 1 + ]); + //Create a task self service + $task4 = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Assign a user in the task + factory(TaskUser::class, 1)->create([ + 'TAS_UID' => $task4[0]->TAS_UID, + 'USR_UID' => $group[0]->GRP_UID, + 'TU_RELATION' => 2, //Related to the group + 'TU_TYPE' => 1 + ]); + //Create the register in list unassigned related to the task1 + factory(ListUnassigned::class, 15)->create([ + 'TAS_ID' => $task1[0]->TAS_ID + ]); + //Create the register in list unassigned related to the task2 + factory(ListUnassigned::class, 15)->create([ + 'TAS_ID' => $task2[0]->TAS_ID + ]); + //Create the register in list unassigned related to the task3 + factory(ListUnassigned::class, 15)->create([ + 'TAS_ID' => $task3[0]->TAS_ID + ]); + //Create the register in list unassigned related to the task4 + factory(ListUnassigned::class, 15)->create([ + 'TAS_ID' => $task4[0]->TAS_ID + ]); + $timeStart = microtime(true); + $result = ListUnassigned::doCount($user[0]->USR_UID); + $timeEnd = microtime(true); + $this->assertEquals(60, $result); + $time = $timeEnd - $timeStart; + error_log('it_should_count_cases_by_user_with_self_service_user_and_group_assigned_parallel_task took [60]--->' . $time); + } + + /** + * This checks the counters is working properly in self-service-value-based with GRP_UID and USR_UID in parallel task + * When the value assigned in the variable @@ARRAY_OF_USERS = [GRP_UID, USR_UID] + * @covers ListUnassigned::doCount + * @test + */ + public function it_should_count_cases_by_user_with_self_service_value_based_usr_uid_and_grp_uid() + { + //Create process + $process = factory(Process::class, 1)->create(); + //Create a case + $application = factory(Application::class, 1)->create(); + //Create user + $user = factory(User::class, 1)->create(); + //Create a task1 self service value based + $task1 = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '@@ARRAY_OF_USERS', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Create the relation for the value assigned in the TAS_GROUP_VARIABLE + $appSelfValue = factory(AppAssignSelfServiceValue::class, 1)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'TAS_ID' => $task1[0]->TAS_ID + ]); + factory(AppAssignSelfServiceValueGroup::class, 1)->create([ + 'ID' => $appSelfValue[0]->ID, + 'GRP_UID' => $user[0]->USR_UID, + 'ASSIGNEE_ID' => $user[0]->USR_ID, //The usrId or grpId + 'ASSIGNEE_TYPE' => 1 //Related to the user=1 related to the group=2 + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 10)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'DEL_INDEX' => $appSelfValue[0]->DEL_INDEX, + 'TAS_ID' => $task1[0]->TAS_ID, + ]); + //Create a task2 self service value based + $task2 = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '@@ARRAY_OF_USERS', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Create the relation for the value assigned in the TAS_GROUP_VARIABLE + $appSelfValue = factory(AppAssignSelfServiceValue::class, 1)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'TAS_ID' => $task2[0]->TAS_ID + ]); + factory(AppAssignSelfServiceValueGroup::class, 1)->create([ + 'ID' => $appSelfValue[0]->ID, + 'GRP_UID' => $user[0]->USR_UID, + 'ASSIGNEE_ID' => $user[0]->USR_ID, //The usrId or grpId + 'ASSIGNEE_TYPE' => 1 //Related to the user=1 related to the group=2 + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 10)->create([ + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'DEL_INDEX' => $appSelfValue[0]->DEL_INDEX, + 'TAS_ID' => $task2[0]->TAS_ID, + ]); + $timeStart = microtime(true); + $result = ListUnassigned::doCount($user[0]->USR_UID); + $this->assertEquals(20, $result); + $timeEnd = microtime(true); + $time = $timeEnd - $timeStart; + error_log('it_should_count_cases_by_user_with_self_service_value_based_usr_uid_and_grp_uid took [20]--->' . $time); + } + + /** + * This checks to make sure pagination is working properly + * @covers ListUnassigned::loadList + * @test + */ + public function it_should_return_pages_of_data() + { + //Create process + $process = factory(Process::class, 1)->create(); + //Create user + $user = factory(User::class, 1)->create(); + //Create a task self service + $task = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Assign a user in the task + factory(TaskUser::class, 1)->create([ + 'TAS_UID' => $task[0]->TAS_UID, + 'USR_UID' => $user[0]->USR_UID, + 'TU_RELATION' => 1, //Related to the user + 'TU_TYPE' => 1 + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 51)->create([ + 'TAS_ID' => $task[0]->TAS_ID + ]); + //Define the filters + $filters = ['start' => 0, 'limit' => 25]; + //Get data first page + $result = ListUnassigned::loadList($user[0]->USR_UID, $filters); + $this->assertCount(25, $result); + //Get data second page + $filters = ['start' => 25, 'limit' => 25]; + $result = ListUnassigned::loadList($user[0]->USR_UID, $filters); + $this->assertCount(25, $result); + //Get data third page + $filters = ['start' => 50, 'limit' => 25]; + $result = ListUnassigned::loadList($user[0]->USR_UID, $filters); + $this->assertCount(1, $result); + } + + /** + * This ensures ordering ascending and descending works by case number APP_NUMBER + * @covers ListUnassigned::loadList + * @test + */ + public function it_should_sort_by_case_number() + { + //Create process + $process = factory(Process::class, 1)->create(); + //Create user + $user = factory(User::class, 1)->create(); + //Create a task self service + $task = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Assign a user in the task + factory(TaskUser::class, 1)->create([ + 'TAS_UID' => $task[0]->TAS_UID, + 'USR_UID' => $user[0]->USR_UID, + 'TU_RELATION' => 1, //Related to the user + 'TU_TYPE' => 1 + ]); + //Create a case + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 3000 + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 1)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + //Create a case + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2000 + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 1)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'APP_NUMBER' => $application[0]->APP_NUMBER + ]); + //Define the filters + $filters = ['sort' => 'APP_NUMBER', 'dir' => 'ASC']; + //Get data + $result = ListUnassigned::loadList($user[0]->USR_UID, $filters); + $this->assertCount(2, $result); + //Get the minor case number first + $this->assertEquals(2000, $result[0]['APP_NUMBER']); + //Get the major case number second + $this->assertEquals(3000, $result[1]['APP_NUMBER']); + //Define the filters + $filters = ['sort' => 'APP_NUMBER', 'dir' => 'DESC']; + //Get data + $result = ListUnassigned::loadList($user[0]->USR_UID, $filters); + $this->assertCount(2, $result); + //Get the major case number first + $this->assertEquals(3000, $result[0]['APP_NUMBER']); + //Get the minor case number second + $this->assertEquals(2000, $result[1]['APP_NUMBER']); + } + + /** + * This ensures ordering ascending and descending works by case number APP_TITLE + * @covers ListUnassigned::loadList + * @test + */ + public function it_should_sort_by_case_title() + { + //Create process + $process = factory(Process::class, 1)->create(); + //Create user + $user = factory(User::class, 1)->create(); + //Create a task self service + $task = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Assign a user in the task + factory(TaskUser::class, 1)->create([ + 'TAS_UID' => $task[0]->TAS_UID, + 'USR_UID' => $user[0]->USR_UID, + 'TU_RELATION' => 1, //Related to the user + 'TU_TYPE' => 1 + ]); + //Create a case + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 3001 + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 1)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'APP_TITLE' => 'Request nro ' . $application[0]->APP_NUMBER, + ]); + //Create a case + $application = factory(Application::class, 1)->create([ + 'APP_NUMBER' => 2001 + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 1)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'APP_TITLE' => 'Request nro ' . $application[0]->APP_NUMBER, + ]); + //Define the filters + $filters = ['sort' => 'APP_TITLE', 'dir' => 'ASC']; + //Get data + $result = ListUnassigned::loadList($user[0]->USR_UID, $filters); + $this->assertCount(2, $result); + //Get the minor case title first + $this->assertEquals('Request nro 2001', $result[0]['APP_TITLE']); + //Get the major case title second + $this->assertEquals('Request nro 3001', $result[1]['APP_TITLE']); + //Define the filters + $filters = ['sort' => 'APP_TITLE', 'dir' => 'DESC']; + //Get data + $result = ListUnassigned::loadList($user[0]->USR_UID, $filters); + $this->assertCount(2, $result); + //Get the major case title first + $this->assertEquals('Request nro 3001', $result[0]['APP_TITLE']); + //Get the minor case title second + $this->assertEquals('Request nro 2001', $result[1]['APP_TITLE']); + } + + /** + * This ensures ordering ascending and descending works by case number APP_PRO_TITLE + * @covers ListUnassigned::loadList + * @test + */ + public function it_should_sort_by_process() + { + //Create user + $user = factory(User::class, 1)->create(); + //Create process + $process = factory(Process::class, 1)->create(); + //Create a task self service + $task = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Assign a user in the task + factory(TaskUser::class, 1)->create([ + 'TAS_UID' => $task[0]->TAS_UID, + 'USR_UID' => $user[0]->USR_UID, + 'TU_RELATION' => 1, //Related to the user + 'TU_TYPE' => 1 + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 1)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'APP_PRO_TITLE' => 'Egypt Supplier Payment Proposal', + ]); + + //Create the register in list unassigned + factory(ListUnassigned::class, 1)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'APP_PRO_TITLE' => 'Russia Supplier Payment Proposal', + ]); + //Define the filters + $filters = ['sort' => 'APP_PRO_TITLE', 'dir' => 'ASC']; + //Get data + $result = ListUnassigned::loadList($user[0]->USR_UID, $filters); + $this->assertCount(2, $result); + //Get the minor process name first + $this->assertEquals('Egypt Supplier Payment Proposal', $result[0]['APP_PRO_TITLE']); + //Get the major process name second + $this->assertEquals('Russia Supplier Payment Proposal', $result[1]['APP_PRO_TITLE']); + //Define the filters + $filters = ['sort' => 'APP_PRO_TITLE', 'dir' => 'DESC']; + //Get data + $result = ListUnassigned::loadList($user[0]->USR_UID, $filters); + $this->assertCount(2, $result); + //Get the major process name first + $this->assertEquals('Russia Supplier Payment Proposal', $result[0]['APP_PRO_TITLE']); + //Get the minor process name second + $this->assertEquals('Egypt Supplier Payment Proposal', $result[1]['APP_PRO_TITLE']); + } + + /** + * This ensures ordering ascending and descending works by case number APP_TAS_TITLE + * @covers ListUnassigned::loadList + * @test + */ + public function it_should_sort_by_task() + { + //Create user + $user = factory(User::class, 1)->create(); + //Create process + $process = factory(Process::class, 1)->create(); + //Create a task self service + $task = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Assign a user in the task + factory(TaskUser::class, 1)->create([ + 'TAS_UID' => $task[0]->TAS_UID, + 'USR_UID' => $user[0]->USR_UID, + 'TU_RELATION' => 1, //Related to the user + 'TU_TYPE' => 1 + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 1)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'APP_TAS_TITLE' => 'Initiate Request', + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 1)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'APP_TAS_TITLE' => 'Waiting for AP Manager Validation', + ]); + //Define the filters + $filters = ['sort' => 'APP_TAS_TITLE', 'dir' => 'ASC']; + //Get data + $result = ListUnassigned::loadList($user[0]->USR_UID, $filters); + $this->assertCount(2, $result); + //Get the minor task name first + $this->assertEquals('Initiate Request', $result[0]['APP_TAS_TITLE']); + //Get the major task name second + $this->assertEquals('Waiting for AP Manager Validation', $result[1]['APP_TAS_TITLE']); + //Define the filters + $filters = ['sort' => 'APP_TAS_TITLE', 'dir' => 'DESC']; + //Get data + $result = ListUnassigned::loadList($user[0]->USR_UID, $filters); + $this->assertCount(2, $result); + //Get the major task name first + $this->assertEquals('Waiting for AP Manager Validation', $result[0]['APP_TAS_TITLE']); + //Get the minor task namesecond + $this->assertEquals('Initiate Request', $result[1]['APP_TAS_TITLE']); + } + + /** + * This checks to make sure filter by category is working properly + * @covers ListUnassigned::loadList + * @test + */ + public function it_should_return_data_filtered_by_process_category() + { + //Create user + $user = factory(User::class, 1)->create(); + //Create a category + $category = factory(ProcessCategory::class, 1)->create(); + //Create process + $process = factory(Process::class, 1)->create([ + 'PRO_CATEGORY' => $category[0]->CATEGORY_UID + ]); + //Create a category + $category1 = factory(ProcessCategory::class, 1)->create(); + //Create process + $process1 = factory(Process::class, 1)->create([ + 'PRO_CATEGORY' => $category1[0]->CATEGORY_UID + ]); + //Create a task self service + $task = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Assign a user in the task + factory(TaskUser::class, 1)->create([ + 'TAS_UID' => $task[0]->TAS_UID, + 'USR_UID' => $user[0]->USR_UID, + 'TU_RELATION' => 1, //Related to the user + 'TU_TYPE' => 1 + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 2)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'PRO_UID' => $process[0]->PRO_UID, + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 5)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'PRO_UID' => $process1[0]->PRO_UID, + ]); + //Get all data + $result = ListUnassigned::loadList($user[0]->USR_UID); + $this->assertCount(7, $result); + //Define the filters + $filters = ['category' => $category[0]->CATEGORY_UID]; + //Get data + $result = ListUnassigned::loadList($user[0]->USR_UID, $filters); + $this->assertCount(2, $result); + //Get the minor case number first + $this->assertEquals($category[0]->CATEGORY_UID, $result[0]['PRO_CATEGORY']); + //Get the major case number second + $this->assertEquals($category[0]->CATEGORY_UID, $result[1]['PRO_CATEGORY']); + } + + /** + * This checks to make sure filter by category is working properly + * @covers ListUnassigned::loadList + * @test + */ + public function it_should_return_data_filtered_by_generic_search() + { + //Create user + $user = factory(User::class, 1)->create(); + //Create process + $process = factory(Process::class, 1)->create(); + //Create a task self service + $task = factory(Task::class, 1)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process[0]->PRO_UID + ]); + //Assign a user in the task + factory(TaskUser::class, 1)->create([ + 'TAS_UID' => $task[0]->TAS_UID, + 'USR_UID' => $user[0]->USR_UID, + 'TU_RELATION' => 1, //Related to the user + 'TU_TYPE' => 1 + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 2)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'APP_TITLE' => 'This is a case name', + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 2)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'APP_PRO_TITLE' => 'This is a process name', + ]); + //Create the register in list unassigned + factory(ListUnassigned::class, 2)->create([ + 'TAS_ID' => $task[0]->TAS_ID, + 'APP_TAS_TITLE' => 'This is a task name', + ]); + //Create other registers + factory(ListUnassigned::class, 4)->create([ + 'TAS_ID' => $task[0]->TAS_ID + ]); + //Define the filters + $filters = ['search' => 'case name']; + //Get data related to the search + $result = ListUnassigned::loadList($user[0]->USR_UID, $filters); + $this->assertCount(2, $result); + //Define the filters + $filters = ['search' => 'process name']; + //Get data related to the search + $result = ListUnassigned::loadList($user[0]->USR_UID, $filters); + $this->assertCount(2, $result); + //Define the filters + $filters = ['search' => 'task name']; + //Get data related to the search + $result = ListUnassigned::loadList($user[0]->USR_UID, $filters); + $this->assertCount(2, $result); + } +} + diff --git a/tests/unit/workflow/engine/src/ProcessMaker/Util/Helpers/GetDiffBetweenModifiedVariablesTest.php b/tests/unit/workflow/engine/src/ProcessMaker/Util/Helpers/GetDiffBetweenModifiedVariablesTest.php new file mode 100644 index 000000000..db6ca1ce3 --- /dev/null +++ b/tests/unit/workflow/engine/src/ProcessMaker/Util/Helpers/GetDiffBetweenModifiedVariablesTest.php @@ -0,0 +1,588 @@ + 'b', + ]; + $source = [ + 'a' => 'b', + ]; + $this->assertEquals([], getDiffBetweenModifiedVariables($change, $source)); + } + + /** + * Test to make sure a diff contains nothing if the source has additional properties but the change does not have them + * Reviewing: string + * @test + */ + public function it_should_return_empty_diff_with_source_having_extra_properties() + { + // Create two of the same associative arrays + $change = [ + 'a' => 'b', + ]; + $source = [ + 'a' => 'b', + 'c' => 'd', + ]; + $this->assertEquals([], getDiffBetweenModifiedVariables($change, $source)); + } + + /** + * Test to make sure a diff contains an extra property if the change has it but source does not + * Reviewing: string + * @test + */ + public function it_should_return_simple_diff_with_change_having_extra_property() + { + // Create two of the same associative arrays + $change = [ + 'a' => 'b', + 'c' => 'd', + ]; + $source = [ + 'a' => 'b', + ]; + $expected = [ + 'c' => 'd', + ]; + $this->assertEquals($expected, getDiffBetweenModifiedVariables($change, $source)); + } + + /** + * Test to make sure the diff includes a property that is in a nested deep array and object property + * @test + */ + public function it_should_return_diff_with_nested_difference() + { + $object1 = new stdClass(); + $object1->h = 'i'; + $object1->j = 'Goodbye'; + $change = [ + 'a' => 'b', + 'c' => [ + 'd' => 'e', + 'f' => 'Goodbye', + ], + 'g' => $object1 + ]; + $object2 = new stdClass(); + $object2->h = 'i'; + $object2->j = 'Hello'; + $source = [ + 'a' => 'b', + 'c' => [ + 'd' => 'e', + 'f' => 'Hello', + ], + 'g' => $object2 + ]; + $object1 = new stdClass(); + $object1->h = 'i'; + $object1->j = 'Goodbye'; + $expected = [ + 'c' => [ + 'd' => 'e', + 'f' => 'Goodbye', + ], + 'g' => $object1 + ]; + $this->assertEquals($expected, getDiffBetweenModifiedVariables($change, $source)); + } + + /** + * Test to make sure the diff includes changes in a nested array + * @test + */ + public function it_should_return_a_diff_with_array_changes() + { + $change = [ + 'var1' => 'A', + 'var2' => 'X', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + 2 => ['field1' => 'AA', 'field2' => 'BB'] + ] + ]; + $source = [ + 'var1' => 'A', + 'var2' => 'B', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'] + ] + ]; + $expected = [ + 'var2' => 'X', + 'grid1' => [ + // Note, the entire array will be updated + 1 => ['field1' => 'A', 'field2' => 'B'], + 2 => ['field1' => 'AA', 'field2' => 'BB'] + ] + ]; + $this->assertEquals($expected, getDiffBetweenModifiedVariables($change, $source)); + } + + /** + * Ensure that the diff provided can be merged with source array to show added rows with proper indexes + * @test + */ + public function it_should_provide_diff_with_merge_that_supports_added_rows_to_array() + { + $change = [ + 'var1' => 'A', + 'var2' => 'X', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + 2 => ['field1' => 'AA', 'field2' => 'BB'] + ] + ]; + $source = [ + 'var1' => 'A', + 'var2' => 'B', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'] + ] + ]; + // Now, let's make sure that when we array replace recursive, it properly has all rows and changes + $expected = [ + 'var1' => 'A', + 'var2' => 'X', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + 2 => ['field1' => 'AA', 'field2' => 'BB'] + ] + ]; + $diff = getDiffBetweenModifiedVariables($change, $source); + $collection = collect($source); + $merged = $collection->merge($diff); + $merged = $merged->all(); + $this->assertEquals($expected, $merged); + } + + /** + * Test to make sure it provides a diff that can be used with replace_recursive to modify an array in place + * @test + */ + public function it_should_provide_diff_with_merge_that_supports_modifying_rows_in_array() + { + $change = [ + 'var1' => 'A', + 'var2' => 'X', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + 2 => ['field1' => 'AA', 'field2' => 'CC'], + 3 => ['field1' => 'AAA', 'field2' => 'BBB'] + ] + ]; + $source = [ + 'var1' => 'A', + 'var2' => 'B', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + 2 => ['field1' => 'AA', 'field2' => 'BB'], + 3 => ['field1' => 'AAA', 'field2' => 'BBB'] + ] + ]; + // Now, let's make sure that when we array replace recursive, it properly has all rows and changes + $expected = [ + 'var1' => 'A', + 'var2' => 'X', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + // Note the changed record at 2 + 2 => ['field1' => 'AA', 'field2' => 'CC'], + 3 => ['field1' => 'AAA', 'field2' => 'BBB'] + ] + ]; + $diff = getDiffBetweenModifiedVariables($change, $source); + $collection = collect($source); + $merged = $collection->merge($diff); + $merged = $merged->all(); + $this->assertEquals($expected, $merged); + } + + /** + * Ensure that the diff can be applied to source to REMOVE records from the array + * @note This will absolutely fail, because you can't apply the diff to remove something, it's not possible in this way + * @test + */ + public function it_should_provide_diff_with_merge_that_supports_removed_rows_from_array() + { + $change = [ + 'var1' => 'A', + 'var2' => 'X', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + ] + ]; + $source = [ + 'var1' => 'A', + 'var2' => 'B', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + 2 => ['field1' => 'AA', 'field2' => 'BB'] + ] + ]; + // Now, let's make sure that when we array replace recursive, it properly has all rows and changes + $expected = [ + 'var1' => 'A', + 'var2' => 'X', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'] + ] + ]; + $diff = getDiffBetweenModifiedVariables($change, $source); + $collection = collect($source); + $merged = $collection->merge($diff); + $merged = $merged->all(); + $this->assertEquals($expected, $merged); + } + + /** + * Utilize new behavior using laravel collections to map and filter to create the desired merged array + * @test + */ + public function it_should_utilize_laravel_collections_to_map_and_filter_for_desired_final_array() + { + $change = [ + 'var1' => 'A', + // Note the changed var 2 + 'var2' => 'X', + // Note the missing var3 element + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + // Note the missing record at index 2 + ] + ]; + $source = [ + 'var1' => 'A', + 'var2' => 'B', + 'var3' => 'C', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + 2 => ['field1' => 'AA', 'field2' => 'BB'] + ] + ]; + // Now, let's make sure that when we array replace recursive, it properly has all rows and changes + $expected = [ + 'var1' => 'A', + 'var2' => 'X', + // Note we don't have var3 + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'] + // And we should not have index 2 + ] + ]; + $diff = getDiffBetweenModifiedVariables($change, $source); + $merged = array_replace_recursive($source, $diff); + // Now collect and map + $final = collect($merged)->filter(function ($value, $key) use ($change) { + // Only accept properties that exist in the change + return array_key_exists($key, $change); + })->map(function ($item, $key) use ($change) { + // We aren't recursively calling, but that's not needed for our situation, so we'll + // Check if it's an array, if so, create a collection, filter, then return the array + if (is_array($item)) { + return collect($item)->filter(function ($value, $subkey) use ($change, $key) { + return array_key_exists($subkey, $change[$key]); + })->all(); + } + + // Otherwise, just return item + return $item; + })->all(); + $this->assertEquals($expected, $final); + } + + /** + * Test to make sure the diff includes changes in a nested array + * @test + */ + public function it_should_return_a_diff_with_object_changes() + { + $person1 = new stdClass(); + $person1->firstName = 'Corine'; + $person1->lastName = 'Martell'; + $change = [ + 'var1' => 'A', + 'var2' => 'X', + 'varPerson' => $person1 + ]; + + $person2 = new stdClass(); + $person2->firstName = 'Corine'; + $person2->lastName = 'Erler'; + $source = [ + 'var1' => 'A', + 'var2' => 'B', + 'varPerson' => $person2 + ]; + $person1 = new stdClass(); + $person1->firstName = 'Corine'; + $person1->lastName = 'Martell'; + $expected = [ + 'var2' => 'X', + 'varPerson' => $person1 + ]; + $this->assertEquals($expected, getDiffBetweenModifiedVariables($change, $source)); + } + + /** + * Ensure that the diff provided can be merged with source object to show added rows with proper indexes + * @test + */ + public function it_should_provide_diff_with_merge_that_supports_added_rows_to_object() + { + $person1 = new stdClass(); + $person1->firstName = 'Corine'; + $person1->lastName = 'Martell'; + $person1->address = '2789 Parkview Drive'; + $change = [ + 'var1' => 'A', + 'var2' => 'X', + 'varPerson' => $person1 + ]; + $person2 = new stdClass(); + $person2->firstName = 'Corine'; + $person2->lastName = 'Erler'; + $source = [ + 'var1' => 'A', + 'var2' => 'B', + 'varPerson' => $person2 + ]; + // Now, let's make sure that when we array replace recursive, it properly has all rows and changes + $person1 = new stdClass(); + $person1->firstName = 'Corine'; + $person1->lastName = 'Martell'; + $person1->address = '2789 Parkview Drive'; + $expected = [ + 'var1' => 'A', + 'var2' => 'X', + 'varPerson' => $person1 + ]; + $diff = getDiffBetweenModifiedVariables($change, $source); + $collection = collect($source); + $merged = $collection->merge($diff); + $merged = $merged->all(); + $this->assertEquals($expected, $merged); + } + + /** + * Test to make sure it provides a diff that can be used with replace_recursive to modify an object in place + * @test + */ + public function it_should_provide_diff_with_merge_that_supports_modifying_rows_in_object() + { + $person1 = new stdClass(); + $person1->firstName = 'Corine'; + $person1->lastName = 'Martell'; + $person1->address = '2789 Parkview Drive'; + $change = [ + 'var1' => 'A', + 'var2' => 'X', + 'varPerson' => $person1 + ]; + $person2 = new stdClass(); + $person2->firstName = 'Corine'; + $person2->lastName = 'Martell'; + $person2->address = '2789 Parkview Drive'; + $source = [ + 'var1' => 'A', + 'var2' => 'B', + 'varPerson' => $person2 + ]; + // Now, let's make sure that when we array replace recursive, it properly has all rows and changes + $person1 = new stdClass(); + $person1->firstName = 'Corine'; + $person1->lastName = 'Martell'; + $person1->address = '2789 Parkview Drive'; + $expected = [ + 'var1' => 'A', + 'var2' => 'X', + 'varPerson' => $person1 + ]; + $diff = getDiffBetweenModifiedVariables($change, $source); + $collection = collect($source); + $merged = $collection->merge($diff); + $merged = $merged->all(); + $this->assertEquals($expected, $merged); + } + + /** + * Ensure that the diff can be applied to source to REMOVE records from the object + * @test + */ + public function it_should_provide_diff_with_merge_that_supports_removed_rows_from_object() + { + $person1 = new stdClass(); + $person1->lastName = 'Gail'; + $person1->address = '3607 Sycamore Road'; + $change = [ + 'var1' => 'A', + 'var2' => 'X', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + 2 => ['field1' => 'AA', 'varPerson' => $person1], + 3 => ['field1' => 'AAA', 'field2' => 'BBB'] + ], + 'varPerson' => $person1 + ]; + $person2 = new stdClass(); + $person2->firstName = 'Corine'; + $person2->lastName = 'Martell'; + $person2->address = '2789 Parkview Drive'; + $source = [ + 'var1' => 'A', + 'var2' => 'B', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + 2 => ['field1' => 'AA', 'varPerson' => $person2], + 3 => ['field1' => 'AAA', 'field2' => 'BBB'] + ], + 'varPerson' => $person2 + ]; + // Now, let's make sure that when we has object variable we need to replace with the last change over the object + $person1 = new stdClass(); + $person1->lastName = 'Gail'; + $person1->address = '3607 Sycamore Road'; + $expected = [ + 'var1' => 'A', + 'var2' => 'X', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + 2 => ['field1' => 'AA', 'varPerson' => $person1], + 3 => ['field1' => 'AAA', 'field2' => 'BBB'] + ], + 'varPerson' => $person1 + ]; + + $diff = getDiffBetweenModifiedVariables($change, $source); + $collection = collect($source); + $merged = $collection->merge($diff); + $merged = $merged->all(); + $this->assertEquals($expected, $merged); + } + + /** + * Ensure that the diff can be applied to source to REMOVE records from the object + * @test + */ + public function it_should_provide_diff_with_merge_in_the_same_object() + { + $person2 = new stdClass(); + $person2->firstName = 'Corine'; + $person2->lastName = 'Martell'; + $person2->address = '2789 Parkview Drive'; + $source = [ + 'var1' => 'A', + 'var2' => 'B', + 'varPerson' => $person2 + ]; + + $person2->lastName = 'Gail'; + $person2->email = 'corine.gail@email.com'; + $change = [ + 'var1' => 'A', + 'var2' => 'X', + 'varPerson' => $person2 + ]; + + // Now, let's make sure that when we has object variable we need to replace with the last change over the object + $person1 = new stdClass(); + $person1->firstName = 'Corine'; + $person1->lastName = 'Martell'; + $person1->address = '2789 Parkview Drive'; + $person1->lastName = 'Gail'; + $person1->email = 'corine.gail@email.com'; + $expected = [ + 'var1' => 'A', + 'var2' => 'X', + 'varPerson' => $person1 + ]; + $diff = getDiffBetweenModifiedVariables($change, $source); + $collection = collect($source); + $merged = $collection->merge($diff); + $merged = $merged->all(); + $this->assertEquals($expected, $merged); + } + + /** + * Ensure that the diff can be applied to source to REMOVE records from nested object + * @test + */ + public function it_should_provide_diff_with_merge_that_supports_rows_from_nested_object() + { + $person1 = new stdClass(); + $person1->firstName = 'Gail'; + $person1->lastName = 'Martell'; + $person1->address = '3607 Sycamore Road'; + $email1 = new stdClass(); + $email1->personal = 'gail@personal.com'; + $email1->coorporative = 'gail@coorporative.com'; + $person1->email = $email1; + $change = [ + 'var1' => 'A', + 'var2' => 'X', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + 2 => ['field1' => 'AA', 'varPerson' => $person1], + 3 => ['field1' => 'AAA', 'field2' => 'BBB'] + ], + 'varPerson' => $person1 + ]; + $person2 = new stdClass(); + $person2->firstName = 'Corine'; + $person2->lastName = 'Martell'; + $email2 = new stdClass(); + $email2->new = 'GailJMartell@email.com'; + $person2->email = $email2; + $source = [ + 'var1' => 'A', + 'var2' => 'B', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + 2 => ['field1' => 'AA', 'varPerson' => $person2], + 3 => ['field1' => 'AAA', 'field2' => 'BBB'] + ], + 'varPerson' => $person2 + ]; + // Now, let's make sure that when we has object variable we need to replace with the last change over the object + $person1 = new stdClass(); + $person1->firstName = 'Gail'; + $person1->lastName = 'Martell'; + $person1->address = '3607 Sycamore Road'; + $email1 = new stdClass(); + $email1->personal = 'gail@personal.com'; + $email1->coorporative = 'gail@coorporative.com'; + $person1->email = $email1; + $expected = [ + 'var1' => 'A', + 'var2' => 'X', + 'grid1' => [ + 1 => ['field1' => 'A', 'field2' => 'B'], + 2 => ['field1' => 'AA', 'varPerson' => $person1], + 3 => ['field1' => 'AAA', 'field2' => 'BBB'] + ], + 'varPerson' => $person1 + ]; + + $diff = getDiffBetweenModifiedVariables($change, $source); + $collection = collect($source); + $merged = $collection->merge($diff); + $merged = $merged->all(); + $this->assertEquals($expected, $merged); + } +} + diff --git a/thirdparty/creole/contrib/DBArrayConnection.php b/thirdparty/creole/contrib/DBArrayConnection.php index a7cbcff75..9b8edef71 100644 --- a/thirdparty/creole/contrib/DBArrayConnection.php +++ b/thirdparty/creole/contrib/DBArrayConnection.php @@ -523,19 +523,15 @@ class DBArrayConnection implements Connection } } - //prepend the headers in the resultRow - array_unshift($resultRow, $this->_DBArray[$tableName][0]); - //$resultRow[0] = $this->_DBArray[ $tableName ][0]; - - /* algorith to order a multiarray - // Obtain a list of columns - foreach ($data as $key => $row) { - $volume[$key] = $row['volume']; - $edition[$key] = $row['edition']; - } - // Sort the data with volume descending, edition ascending - // Add $data as the last parameter, to sort by the common key - array_multisort($volume, SORT_DESC, $edition, SORT_ASC, $data); */ + /** + * Prepend the headers in the resultRow. + * If the null value is not taken, $resultRow will lose an element. + */ + $header = null; + if (isset($this->_DBArray[$tableName][0])) { + $header = $this->_DBArray[$tableName][0]; + } + array_unshift($resultRow, $header); /* * Apply Limit and Offset diff --git a/thirdparty/creole/drivers/mssql/MSSQLConnection.php b/thirdparty/creole/drivers/mssql/MSSQLConnection.php index b9097ee4f..0135300a2 100644 --- a/thirdparty/creole/drivers/mssql/MSSQLConnection.php +++ b/thirdparty/creole/drivers/mssql/MSSQLConnection.php @@ -83,7 +83,8 @@ class MSSQLConnection extends ConnectionCommon implements Connection $opt = [ 'UID' => $user, 'PWD' => $pw, - 'Database' => $dsninfo['database'] + 'Database' => $dsninfo['database'], + 'CharacterSet' => 'UTF-8' ]; // SQLSrv is persistent always $conn = sqlsrv_connect($dbhost, $opt); @@ -191,16 +192,18 @@ class MSSQLConnection extends ConnectionCommon implements Connection { $this->lastQuery = $sql; if (extension_loaded('sqlsrv')) { - $result = sqlsrv_query($this->dblink, $sql); + $result = @sqlsrv_query($this->dblink, $sql); + if (!$result) { + throw new SQLException('Could not execute query', print_r(sqlsrv_errors(), true)); + } } else { if (!@mssql_select_db($this->database, $this->dblink)) { throw new SQLException('No database selected'); } - $result = @mssql_query($sql, $this->dblink); - } - if (!$result) { - throw new SQLException('Could not execute query', mssql_get_last_message()); + if (!$result) { + throw new SQLException('Could not execute query', mssql_get_last_message()); + } } return new MSSQLResultSet($this, $result, $fetchmode); } @@ -210,23 +213,23 @@ class MSSQLConnection extends ConnectionCommon implements Connection */ function executeUpdate($sql) { + $this->lastQuery = $sql; if (extension_loaded('sqlsrv')) { - $result = sqlsrv_query($this->dblink, $sql); + $result = @sqlsrv_query($this->dblink, $sql); + if (!$result) { + throw new SQLException('Could not execute update', print_r(sqlsrv_errors(), true), $sql); + } + return (int) sqlsrv_rows_affected($result); } else { - $this->lastQuery = $sql; if (!mssql_select_db($this->database, $this->dblink)) { throw new SQLException('No database selected'); } - $result = @mssql_query($sql, $this->dblink); + if (!$result) { + throw new SQLException('Could not execute update', mssql_get_last_message(), $sql); + } + return (int) mssql_rows_affected($this->dblink); } - - if (!$result) { - throw new SQLException('Could not execute update', mssql_get_last_message(), $sql); - } - - return (int) mssql_rows_affected($this->dblink); - // return $this->getUpdateCount(); } /** @@ -237,15 +240,18 @@ class MSSQLConnection extends ConnectionCommon implements Connection protected function beginTrans() { if (extension_loaded('sqlsrv')) { - $result = sqlsrv_begin_transaction($this->dblink); + $result = @sqlsrv_begin_transaction($this->dblink); + if (!$result) { + throw new SQLException('Could not begin transaction', print_r(sqlsrv_errors(), true)); + } } else { $result = @mssql_query('BEGIN TRAN', $this->dblink); - } - if (!$result) { - throw new SQLException('Could not begin transaction', mssql_get_last_message()); + if (!$result) { + throw new SQLException('Could not begin transaction', mssql_get_last_message()); + } } } - + /** * Commit the current transaction. * @throws SQLException @@ -254,15 +260,18 @@ class MSSQLConnection extends ConnectionCommon implements Connection protected function commitTrans() { if (extension_loaded('sqlsrv')) { - $result = sqlsrv_commit($this->dblink); + $result = @sqlsrv_commit($this->dblink); + if (!$result) { + throw new SQLException('Could not commit transaction', print_r(sqlsrv_errors(), true)); + } } else { if (!@mssql_select_db($this->database, $this->dblink)) { throw new SQLException('No database selected'); } $result = @mssql_query('COMMIT TRAN', $this->dblink); - } - if (!$result) { - throw new SQLException('Could not commit transaction', mssql_get_last_message()); + if (!$result) { + throw new SQLException('Could not commit transaction', mssql_get_last_message()); + } } } @@ -274,15 +283,18 @@ class MSSQLConnection extends ConnectionCommon implements Connection protected function rollbackTrans() { if (extension_loaded('sqlsrv')) { - $result = sqlsrv_rollback($this->dblink); + $result = @sqlsrv_rollback($this->dblink); + if (!$result) { + throw new SQLException('Could not rollback transaction', print_r(sqlsrv_errors(), true)); + } } else { if (!@mssql_select_db($this->database, $this->dblink)) { throw new SQLException('no database selected'); } $result = @mssql_query('ROLLBACK TRAN', $this->dblink); - } - if (!$result) { - throw new SQLException('Could not rollback transaction', mssql_get_last_message()); + if (!$result) { + throw new SQLException('Could not rollback transaction', mssql_get_last_message()); + } } } diff --git a/thirdparty/creole/drivers/mssql/MSSQLResultSet.php b/thirdparty/creole/drivers/mssql/MSSQLResultSet.php index b75c740e5..b66008179 100644 --- a/thirdparty/creole/drivers/mssql/MSSQLResultSet.php +++ b/thirdparty/creole/drivers/mssql/MSSQLResultSet.php @@ -154,12 +154,14 @@ class MSSQLResultSet extends ResultSetCommon implements ResultSet { if (extension_loaded('sqlsrv')) { $rows = @sqlsrv_num_rows($this->result); + if ($rows === null) { + throw new SQLException('Error getting record count', print_r(sqlsrv_errors(), true)); + } } else { $rows = @mssql_num_rows($this->result); - } - - if ($rows === null) { - throw new SQLException('Error getting record count', mssql_get_last_message()); + if ($rows === null) { + throw new SQLException('Error getting record count', mssql_get_last_message()); + } } // adjust count based on emulated LIMIT/OFFSET $rows -= $this->offset; diff --git a/thirdparty/creole/drivers/mssql/metadata/MSSQLDatabaseInfo.php b/thirdparty/creole/drivers/mssql/metadata/MSSQLDatabaseInfo.php index 959c1e321..3e557eabc 100644 --- a/thirdparty/creole/drivers/mssql/metadata/MSSQLDatabaseInfo.php +++ b/thirdparty/creole/drivers/mssql/metadata/MSSQLDatabaseInfo.php @@ -38,31 +38,30 @@ class MSSQLDatabaseInfo extends DatabaseInfo protected function initTables() { include_once 'creole/drivers/mssql/metadata/MSSQLTableInfo.php'; - $dsn = $this->conn->getDSN(); - - + $sql = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME <> 'dtproperties'"; if (extension_loaded('sqlsrv')) { - $result = sqlsrv_query( - "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME <> 'dtproperties'", - $this->conn->getResource() - ); + $result = sqlsrv_query($sql, $this->conn->getResource()); + if (!$result) { + throw new SQLException("Could not list tables", print_r(sqlsrv_errors(), true)); + } + while ($row = sqlsrv_fetch_array($result)) { + $this->tables[strtoupper($row[0])] = new MSSQLTableInfo($this, $row[0]); + } } else { if (!@mssql_select_db($this->dbname, $this->conn->getResource())) { throw new SQLException('No database selected'); } - $result = mssql_query("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME <> 'dtproperties'", $this->conn->getResource()); - } - - if (!$result) { - throw new SQLException("Could not list tables", mssql_get_last_message()); - } - - while ($row = mssql_fetch_row($result)) { - $this->tables[strtoupper($row[0])] = new MSSQLTableInfo($this, $row[0]); + $result = mssql_query($sql, $this->conn->getResource()); + if (!$result) { + throw new SQLException("Could not list tables", mssql_get_last_message()); + } + while ($row = mssql_fetch_row($result)) { + $this->tables[strtoupper($row[0])] = new MSSQLTableInfo($this, $row[0]); + } } } - + /** * * @return void diff --git a/thirdparty/creole/drivers/mysqli/MySQLiResultSet.php b/thirdparty/creole/drivers/mysqli/MySQLiResultSet.php index fecfd6361..32a9ddaac 100644 --- a/thirdparty/creole/drivers/mysqli/MySQLiResultSet.php +++ b/thirdparty/creole/drivers/mysqli/MySQLiResultSet.php @@ -98,7 +98,9 @@ class MySQLiResultSet extends ResultSetCommon implements ResultSet { */ public function close() { - @mysqli_free_result($this->result); + if (is_resource($this->result)) { + @mysqli_free_result($this->result); + } $this->fields = array(); } diff --git a/thirdparty/pear/DB/mysqli.php b/thirdparty/pear/DB/mysqli.php index 3c0fd1db4..7bd138855 100644 --- a/thirdparty/pear/DB/mysqli.php +++ b/thirdparty/pear/DB/mysqli.php @@ -379,7 +379,13 @@ class DB_mysqli extends DB_common # need to come up with different means for next line # since $result is object (int)$result won't fly... // unset($this->num_rows[(int)$result]); - return @mysqli_free_result($result); + + //for compatibility the method must return a boolean. + if (is_resource($result)) { + @mysqli_free_result($result); + return true; + } + return false; } // }}} @@ -902,7 +908,9 @@ class DB_mysqli extends DB_common // free the result only if we were called on a table if ($got_string) { - @mysqli_free_result($id); + if (is_resource($id)) { + @mysqli_free_result($id); + } } return $res; } diff --git a/thirdparty/phpmailer/class.phpmailer.php b/thirdparty/phpmailer/class.phpmailer.php deleted file mode 100644 index 0bf7d9eb8..000000000 --- a/thirdparty/phpmailer/class.phpmailer.php +++ /dev/null @@ -1,2862 +0,0 @@ -UseSendmailOptions) { - $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($subject)), $body, $header); - } else { - $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($subject)), $body, $header, $params); - } - return $rt; - } - - /** - * Outputs debugging info via user-defined method - * @param string $str - */ - private function edebug($str) { - if ($this->Debugoutput == "error_log") { - error_log($str); - } else { - error_log($str); - } - } - - /** - * Constructor - * @param boolean $exceptions Should we throw external exceptions? - */ - public function __construct($exceptions = false) { - $this->exceptions = ($exceptions == true); - } - - /** - * Sets message type to HTML. - * @param bool $ishtml - * @return void - */ - public function IsHTML($ishtml = true) { - if ($ishtml) { - $this->ContentType = 'text/html'; - } else { - $this->ContentType = 'text/plain'; - } - } - - /** - * Sets Mailer to send message using SMTP. - * @return void - */ - public function IsSMTP() { - $this->Mailer = 'smtp'; - } - - /** - * Sets Mailer to send message using PHP mail() function. - * @return void - */ - public function IsMail() { - $this->Mailer = 'mail'; - } - - /** - * Sets Mailer to send message using the $Sendmail program. - * @return void - */ - public function IsSendmail() { - if (!stristr(ini_get('sendmail_path'), 'sendmail')) { - $this->Sendmail = '/var/qmail/bin/sendmail'; - } - $this->Mailer = 'sendmail'; - } - - /** - * Sets Mailer to send message using the qmail MTA. - * @return void - */ - public function IsQmail() { - if (stristr(ini_get('sendmail_path'), 'qmail')) { - $this->Sendmail = '/var/qmail/bin/sendmail'; - } - $this->Mailer = 'sendmail'; - } - - ///////////////////////////////////////////////// - // METHODS, RECIPIENTS - ///////////////////////////////////////////////// - - /** - * Adds a "To" address. - * @param string $address - * @param string $name - * @return boolean true on success, false if address already used - */ - public function AddAddress($address, $name = '') { - return $this->AddAnAddress('to', $address, $name); - } - - /** - * Adds a "Cc" address. - * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer. - * @param string $address - * @param string $name - * @return boolean true on success, false if address already used - */ - public function AddCC($address, $name = '') { - return $this->AddAnAddress('cc', $address, $name); - } - - /** - * Adds a "Bcc" address. - * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer. - * @param string $address - * @param string $name - * @return boolean true on success, false if address already used - */ - public function AddBCC($address, $name = '') { - return $this->AddAnAddress('bcc', $address, $name); - } - - /** - * Adds a "Reply-to" address. - * @param string $address - * @param string $name - * @return boolean - */ - public function AddReplyTo($address, $name = '') { - return $this->AddAnAddress('Reply-To', $address, $name); - } - - /** - * Adds an address to one of the recipient arrays - * Addresses that have been added already return false, but do not throw exceptions - * @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo' - * @param string $address The email address to send to - * @param string $name - * @throws phpmailerException - * @return boolean true on success, false if address already used or invalid in some way - * @access protected - */ - protected function AddAnAddress($kind, $address, $name = '') { - if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) { - $this->SetError($this->Lang('Invalid recipient array').': '.$kind); - if ($this->exceptions) { - throw new phpmailerException('Invalid recipient array: ' . $kind); - } - if ($this->SMTPDebug) { - $this->edebug($this->Lang('Invalid recipient array').': '.$kind); - } - return false; - } - $address = trim($address); - $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim - if (!$this->ValidateAddress($address)) { - $this->SetError($this->Lang('invalid_address').': '. $address); - if ($this->exceptions) { - throw new phpmailerException($this->Lang('invalid_address').': '.$address); - } - if ($this->SMTPDebug) { - $this->edebug($this->Lang('invalid_address').': '.$address); - } - return false; - } - if ($kind != 'Reply-To') { - if (!isset($this->all_recipients[strtolower($address)])) { - array_push($this->$kind, array($address, $name)); - $this->all_recipients[strtolower($address)] = true; - return true; - } - } else { - if (!array_key_exists(strtolower($address), $this->ReplyTo)) { - $this->ReplyTo[strtolower($address)] = array($address, $name); - return true; - } - } - return false; -} - -/** - * Set the From and FromName properties - * @param string $address - * @param string $name - * @param int $auto Also set Reply-To and Sender - * @throws phpmailerException - * @return boolean - */ - public function SetFrom($address, $name = '', $auto = 1) { - $address = trim($address); - $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim - if (!$this->ValidateAddress($address)) { - $this->SetError($this->Lang('invalid_address').': '. $address); - if ($this->exceptions) { - throw new phpmailerException($this->Lang('invalid_address').': '.$address); - } - if ($this->SMTPDebug) { - $this->edebug($this->Lang('invalid_address').': '.$address); - } - return false; - } - $this->From = $address; - $this->FromName = $name; - if ($auto) { - if (empty($this->ReplyTo)) { - $this->AddAnAddress('Reply-To', $address, $name); - } - if (empty($this->Sender)) { - $this->Sender = $address; - } - } - return true; - } - - /** - * Check that a string looks roughly like an email address should - * Static so it can be used without instantiation, public so people can overload - * Conforms to RFC5322: Uses *correct* regex on which FILTER_VALIDATE_EMAIL is - * based; So why not use FILTER_VALIDATE_EMAIL? Because it was broken to - * not allow a@b type valid addresses :( - * Some Versions of PHP break on the regex though, likely due to PCRE, so use - * the older validation method for those users. (http://php.net/manual/en/pcre.installation.php) - * @link http://squiloople.com/2009/12/20/email-address-validation/ - * @copyright regex Copyright Michael Rushton 2009-10 | http://squiloople.com/ | Feel free to use and redistribute this code. But please keep this copyright notice. - * @param string $address The email address to check - * @return boolean - * @static - * @access public - */ - public static function ValidateAddress($address) { - if ((defined('PCRE_VERSION')) && (version_compare(PCRE_VERSION, '8.0') >= 0)) { - return preg_match('/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)((?>(?>(?>((?>(?>(?>\x0D\x0A)?[ ])+|(?>[ ]*\x0D\x0A)?[ ]+)?)(\((?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}|(?!(?:.*[a-f0-9][:\]]){7,})((?6)(?>:(?6)){0,5})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:|(?!(?:.*[a-f0-9]:){5,})(?8)?::(?>((?6)(?>:(?6)){0,3}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD', $address); - } elseif (function_exists('filter_var')) { //Introduced in PHP 5.2 - if(filter_var($address, FILTER_VALIDATE_EMAIL) === FALSE) { - return false; - } else { - return true; - } - } else { - return preg_match('/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!\.)){0,61}[a-zA-Z0-9_-]?\.)+[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!$)){0,61}[a-zA-Z0-9_]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/', $address); - } - } - - ///////////////////////////////////////////////// - // METHODS, MAIL SENDING - ///////////////////////////////////////////////// - - /** - * Creates message and assigns Mailer. If the message is - * not sent successfully then it returns false. Use the ErrorInfo - * variable to view description of the error. - * @throws phpmailerException - * @return bool - */ - public function Send() { - try { - if(!$this->PreSend()) return false; - return $this->PostSend(); - } catch (phpmailerException $e) { - $this->mailHeader = ''; - $this->SetError($e->getMessage()); - if ($this->exceptions) { - throw $e; - } - return false; - } - } - - /** - * Prep mail by constructing all message entities - * @throws phpmailerException - * @return bool - */ - public function PreSend() { - try { - $this->mailHeader = ""; - if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) { - throw new phpmailerException($this->Lang('provide_address'), self::STOP_CRITICAL); - } - - // Set whether the message is multipart/alternative - if(!empty($this->AltBody)) { - $this->ContentType = 'multipart/alternative'; - } - - $this->error_count = 0; // reset errors - $this->SetMessageType(); - //Refuse to send an empty message - if (empty($this->Body)) { - throw new phpmailerException($this->Lang('empty_message'), self::STOP_CRITICAL); - } - - $this->MIMEHeader = $this->CreateHeader(); - $this->MIMEBody = $this->CreateBody(); - - // To capture the complete message when using mail(), create - // an extra header list which CreateHeader() doesn't fold in - if ($this->Mailer == 'mail') { - if (count($this->to) > 0) { - $this->mailHeader .= $this->AddrAppend("To", $this->to); - } else { - $this->mailHeader .= $this->HeaderLine("To", "undisclosed-recipients:;"); - } - $this->mailHeader .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader(trim($this->Subject)))); - // if(count($this->cc) > 0) { - // $this->mailHeader .= $this->AddrAppend("Cc", $this->cc); - // } - } - - // digitally sign with DKIM if enabled - if (!empty($this->DKIM_domain) && !empty($this->DKIM_private) && !empty($this->DKIM_selector) && !empty($this->DKIM_domain) && file_exists($this->DKIM_private)) { - $header_dkim = $this->DKIM_Add($this->MIMEHeader, $this->EncodeHeader($this->SecureHeader($this->Subject)), $this->MIMEBody); - $this->MIMEHeader = str_replace("\r\n", "\n", $header_dkim) . $this->MIMEHeader; - } - - return true; - - } catch (phpmailerException $e) { - $this->SetError($e->getMessage()); - if ($this->exceptions) { - throw $e; - } - return false; - } - } - - /** - * Actual Email transport function - * Send the email via the selected mechanism - * @throws phpmailerException - * @return bool - */ - public function PostSend() { - try { - // Choose the mailer and send through it - switch($this->Mailer) { - case 'sendmail': - return $this->SendmailSend($this->MIMEHeader, $this->MIMEBody); - case 'smtp': - return $this->SmtpSend($this->MIMEHeader, $this->MIMEBody); - case 'mail': - return $this->MailSend($this->MIMEHeader, $this->MIMEBody); - default: - return $this->MailSend($this->MIMEHeader, $this->MIMEBody); - } - } catch (phpmailerException $e) { - $this->SetError($e->getMessage()); - if ($this->exceptions) { - throw $e; - } - if ($this->SMTPDebug) { - $this->edebug($e->getMessage()."\n"); - } - } - return false; - } - - /** - * Sends mail using the $Sendmail program. - * @param string $header The message headers - * @param string $body The message body - * @throws phpmailerException - * @access protected - * @return bool - */ - protected function SendmailSend($header, $body) { - if ($this->Sender != '') { - $sendmail = sprintf("%s -oi -f%s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); - } else { - $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail)); - } - if ($this->SingleTo === true) { - foreach ($this->SingleToArray as $val) { - if(!@$mail = popen($sendmail, 'w')) { - throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL); - } - fputs($mail, "To: " . $val . "\n"); - fputs($mail, $header); - fputs($mail, $body); - $result = pclose($mail); - // implement call back function if it exists - $isSent = ($result == 0) ? 1 : 0; - $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body); - if($result != 0) { - throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL); - } - } - } else { - if(!@$mail = popen($sendmail, 'w')) { - throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL); - } - fputs($mail, $header); - fputs($mail, $body); - $result = pclose($mail); - // implement call back function if it exists - $isSent = ($result == 0) ? 1 : 0; - $this->doCallback($isSent, $this->to, $this->cc, $this->bcc, $this->Subject, $body); - if($result != 0) { - throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL); - } - } - return true; - } - - /** - * Sends mail using the PHP mail() function. - * @param string $header The message headers - * @param string $body The message body - * @throws phpmailerException - * @access protected - * @return bool - */ - protected function MailSend($header, $body) - { - $toArr = array(); - foreach ($this->to as $t) { - $toArr[] = $this->AddrFormat($t); - } - $to = implode(', ', $toArr); - - if (empty($this->Sender)) { - $params = "-oi "; - } else { - $params = sprintf("-oi -f%s", $this->Sender); - } - if ($this->Sender != '') { - $old_from = ini_get('sendmail_from'); - ini_set('sendmail_from', $this->Sender); - } - $rt = false; - if ($this->SingleTo === true && count($toArr) > 1) { - foreach ($toArr as $val) { - $rt = $this->mail_passthru($val, $this->Subject, $body, $header, $params); - // implement call back function if it exists - $isSent = ($rt == 1) ? 1 : 0; - $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body); - } - } else { - $rt = $this->mail_passthru($to, $this->Subject, $body, $header, $params); - // implement call back function if it exists - $isSent = ($rt == 1) ? 1 : 0; - $this->doCallback($isSent, $to, $this->cc, $this->bcc, $this->Subject, $body); - } - if (isset($old_from)) { - ini_set('sendmail_from', $old_from); - } - if (!$rt) { - throw new phpmailerException($this->Lang('instantiate'), self::STOP_CRITICAL); - } - return true; - } - - /** - * Sends mail via SMTP using PhpSMTP - * Returns false if there is a bad MAIL FROM, RCPT, or DATA input. - * @param string $header The message headers - * @param string $body The message body - * @throws phpmailerException - * @uses SMTP - * @access protected - * @return bool - */ - protected function SmtpSend($header, $body) { - require_once $this->PluginDir . 'class.smtp.php'; - $bad_rcpt = array(); - - if(!$this->SmtpConnect()) { - throw new phpmailerException($this->Lang('smtp_connect_failed'), self::STOP_CRITICAL); - } - $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender; - if(!$this->smtp->Mail($smtp_from)) { - $this->SetError($this->Lang('from_failed') . $smtp_from . " : " . implode(",",$this->smtp->getError())) ; - throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL); - } - - // Attempt to send attach all recipients - foreach($this->to as $to) { - if (!$this->smtp->Recipient($to[0])) { - $bad_rcpt[] = $to[0]; - // implement call back function if it exists - $isSent = 0; - $this->doCallback($isSent, $to[0], '', '', $this->Subject, $body); - } else { - // implement call back function if it exists - $isSent = 1; - $this->doCallback($isSent, $to[0], '', '', $this->Subject, $body); - } - } - foreach($this->cc as $cc) { - if (!$this->smtp->Recipient($cc[0])) { - $bad_rcpt[] = $cc[0]; - // implement call back function if it exists - $isSent = 0; - $this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body); - } else { - // implement call back function if it exists - $isSent = 1; - $this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body); - } - } - foreach($this->bcc as $bcc) { - if (!$this->smtp->Recipient($bcc[0])) { - $bad_rcpt[] = $bcc[0]; - // implement call back function if it exists - $isSent = 0; - $this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body); - } else { - // implement call back function if it exists - $isSent = 1; - $this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body); - } - } - - - if (count($bad_rcpt) > 0 ) { //Create error message for any bad addresses - $badaddresses = implode(', ', $bad_rcpt); - throw new phpmailerException($this->Lang('recipients_failed') . $badaddresses); - } - if(!$this->smtp->Data($header . $body)) { - throw new phpmailerException($this->Lang('data_not_accepted'), self::STOP_CRITICAL); - } - if($this->SMTPKeepAlive == true) { - $this->smtp->Reset(); - } else { - $this->smtp->Quit(); - $this->smtp->Close(); - } - return true; - } - - /** - * Initiates a connection to an SMTP server. - * Returns false if the operation failed. - * @uses SMTP - * @access public - * @throws phpmailerException - * @return bool - */ - public function SmtpConnect() { - if(is_null($this->smtp)) { - $this->smtp = new SMTP; - } - - $this->smtp->Timeout = $this->Timeout; - $this->smtp->do_debug = $this->SMTPDebug; - $hosts = explode(';', $this->Host); - $index = 0; - $connection = $this->smtp->Connected(); - - // Retry while there is no connection - try { - while($index < count($hosts) && !$connection) { - $hostinfo = array(); - if (preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) { - $host = $hostinfo[1]; - $port = $hostinfo[2]; - } else { - $host = $hosts[$index]; - $port = $this->Port; - } - - $tls = ($this->SMTPSecure == 'tls'); - $ssl = ($this->SMTPSecure == 'ssl'); - - if ($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout)) { - - $hello = ($this->Helo != '' ? $this->Helo : $this->ServerHostname()); - $this->smtp->Hello($hello); - - if ($tls) { - if (!$this->smtp->StartTLS()) { - throw new phpmailerException($this->Lang('connect_host')); - } - - //We must resend HELO after tls negotiation - $this->smtp->Hello($hello); - } - - $connection = true; - if ($this->SMTPAuth) { - if (!$this->smtp->Authenticate($this->Username, $this->Password, $this->AuthType, - $this->Realm, $this->Workstation)) { - throw new phpmailerException($this->Lang('authenticate')); - } - } - } - $index++; - if (!$connection) { - throw new phpmailerException($this->Lang('connect_host')); - } - } - } catch (phpmailerException $e) { - $this->smtp->Reset(); - if ($this->exceptions) { - throw $e; - } - } - return true; - } - - /** - * Closes the active SMTP session if one exists. - * @return void - */ - public function SmtpClose() { - if ($this->smtp !== null) { - if($this->smtp->Connected()) { - $this->smtp->Quit(); - $this->smtp->Close(); - } - } - } - - /** - * Sets the language for all class error messages. - * Returns false if it cannot load the language file. The default language is English. - * @param string $langcode ISO 639-1 2-character language code (e.g. Portuguese: "br") - * @param string $lang_path Path to the language file directory - * @return bool - * @access public - */ - function SetLanguage($langcode = 'en', $lang_path = 'language/') { - //Define full set of translatable strings - $PHPMAILER_LANG = array( - 'authenticate' => 'SMTP Error: Could not authenticate.', - 'connect_host' => 'SMTP Error: Could not connect to SMTP host.', - 'data_not_accepted' => 'SMTP Error: Data not accepted.', - 'empty_message' => 'Message body empty', - 'encoding' => 'Unknown encoding: ', - 'execute' => 'Could not execute: ', - 'file_access' => 'Could not access file: ', - 'file_open' => 'File Error: Could not open file: ', - 'from_failed' => 'The following From address failed: ', - 'instantiate' => 'Could not instantiate mail function.', - 'invalid_address' => 'Invalid address', - 'mailer_not_supported' => ' mailer is not supported.', - 'provide_address' => 'You must provide at least one recipient email address.', - 'recipients_failed' => 'SMTP Error: The following recipients failed: ', - 'signing' => 'Signing Error: ', - 'smtp_connect_failed' => 'SMTP Connect() failed.', - 'smtp_error' => 'SMTP server error: ', - 'variable_set' => 'Cannot set or reset variable: ' - ); - //Overwrite language-specific strings. This way we'll never have missing translations - no more "language string failed to load"! - $l = true; - if ($langcode != 'en') { //There is no English translation file - if (substr($langcode, 0, 2) == 'pt') { - $langcode = 'br'; - } - $l = @include $lang_path.'phpmailer.lang-'.$langcode.'.php'; - } - $this->language = $PHPMAILER_LANG; - return ($l == true); //Returns false if language not found - } - - /** - * Return the current array of language strings - * @return array - */ - public function GetTranslations() { - return $this->language; - } - - ///////////////////////////////////////////////// - // METHODS, MESSAGE CREATION - ///////////////////////////////////////////////// - - /** - * Creates recipient headers. - * @access public - * @param string $type - * @param array $addr - * @return string - */ - public function AddrAppend($type, $addr) { - $addr_str = $type . ': '; - $addresses = array(); - foreach ($addr as $a) { - $addresses[] = $this->AddrFormat($a); - } - $addr_str .= implode(', ', $addresses); - $addr_str .= $this->LE; - - return $addr_str; - } - - /** - * Formats an address correctly. - * @access public - * @param string $addr - * @return string - */ - public function AddrFormat($addr) { - if (empty($addr[1])) { - return $this->SecureHeader($addr[0]); - } else { - return $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">"; - } - } - - /** - * Wraps message for use with mailers that do not - * automatically perform wrapping and for quoted-printable. - * Original written by philippe. - * @param string $message The message to wrap - * @param integer $length The line length to wrap to - * @param boolean $qp_mode Whether to run in Quoted-Printable mode - * @access public - * @return string - */ - public function WrapText($message, $length, $qp_mode = false) { - $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE; - // If utf-8 encoding is used, we will need to make sure we don't - // split multibyte characters when we wrap - $is_utf8 = (strtolower($this->CharSet) == "utf-8"); - $lelen = strlen($this->LE); - $crlflen = strlen(self::CRLF); - - $message = $this->FixEOL($message); - if (substr($message, -$lelen) == $this->LE) { - $message = substr($message, 0, -$lelen); - } - - $line = explode($this->LE, $message); // Magic. We know FixEOL uses $LE - $message = ''; - for ($i = 0 ;$i < count($line); $i++) { - $line_part = explode(' ', $line[$i]); - $buf = ''; - for ($e = 0; $e $length)) { - $space_left = $length - strlen($buf) - $crlflen; - if ($e != 0) { - if ($space_left > 20) { - $len = $space_left; - if ($is_utf8) { - $len = $this->UTF8CharBoundary($word, $len); - } elseif (substr($word, $len - 1, 1) == "=") { - $len--; - } elseif (substr($word, $len - 2, 1) == "=") { - $len -= 2; - } - $part = substr($word, 0, $len); - $word = substr($word, $len); - $buf .= ' ' . $part; - $message .= $buf . sprintf("=%s", self::CRLF); - } else { - $message .= $buf . $soft_break; - } - $buf = ''; - } - while (strlen($word) > 0) { - $len = $length; - if ($is_utf8) { - $len = $this->UTF8CharBoundary($word, $len); - } elseif (substr($word, $len - 1, 1) == "=") { - $len--; - } elseif (substr($word, $len - 2, 1) == "=") { - $len -= 2; - } - $part = substr($word, 0, $len); - $word = substr($word, $len); - - if (strlen($word) > 0) { - $message .= $part . sprintf("=%s", self::CRLF); - } else { - $buf = $part; - } - } - } else { - $buf_o = $buf; - $buf .= ($e == 0) ? $word : (' ' . $word); - - if (strlen($buf) > $length and $buf_o != '') { - $message .= $buf_o . $soft_break; - $buf = $word; - } - } - } - $message .= $buf . self::CRLF; - } - - return $message; - } - - /** - * Finds last character boundary prior to maxLength in a utf-8 - * quoted (printable) encoded string. - * Original written by Colin Brown. - * @access public - * @param string $encodedText utf-8 QP text - * @param int $maxLength find last character boundary prior to this length - * @return int - */ - public function UTF8CharBoundary($encodedText, $maxLength) { - $foundSplitPos = false; - $lookBack = 3; - while (!$foundSplitPos) { - $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack); - $encodedCharPos = strpos($lastChunk, "="); - if ($encodedCharPos !== false) { - // Found start of encoded character byte within $lookBack block. - // Check the encoded byte value (the 2 chars after the '=') - $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2); - $dec = hexdec($hex); - if ($dec < 128) { // Single byte character. - // If the encoded char was found at pos 0, it will fit - // otherwise reduce maxLength to start of the encoded char - $maxLength = ($encodedCharPos == 0) ? $maxLength : - $maxLength - ($lookBack - $encodedCharPos); - $foundSplitPos = true; - } elseif ($dec >= 192) { // First byte of a multi byte character - // Reduce maxLength to split at start of character - $maxLength = $maxLength - ($lookBack - $encodedCharPos); - $foundSplitPos = true; - } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back - $lookBack += 3; - } - } else { - // No encoded character found - $foundSplitPos = true; - } - } - return $maxLength; - } - - - /** - * Set the body wrapping. - * @access public - * @return void - */ - public function SetWordWrap() { - if($this->WordWrap < 1) { - return; - } - - switch($this->message_type) { - case 'alt': - case 'alt_inline': - case 'alt_attach': - case 'alt_inline_attach': - $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap); - break; - default: - $this->Body = $this->WrapText($this->Body, $this->WordWrap); - break; - } - } - - /** - * Assembles message header. - * @access public - * @return string The assembled header - */ - public function CreateHeader() { - $result = ''; - - if(!class_exists('G')){ - $realdocuroot = str_replace( '\\', '/', $_SERVER['DOCUMENT_ROOT'] ); - $docuroot = explode( '/', $realdocuroot ); - array_pop( $docuroot ); - $pathhome = implode( '/', $docuroot ) . '/'; - array_pop( $docuroot ); - $pathTrunk = implode( '/', $docuroot ) . '/'; - require_once($pathTrunk.'gulliver/system/class.g.php'); - } - // Set the boundaries - $uniq_id = G::encryptOld(uniqid(time())); - $this->boundary[1] = 'b1_' . $uniq_id; - $this->boundary[2] = 'b2_' . $uniq_id; - $this->boundary[3] = 'b3_' . $uniq_id; - - if ($this->MessageDate == '') { - $result .= $this->HeaderLine('Date', self::RFCDate()); - } else { - $result .= $this->HeaderLine('Date', $this->MessageDate); - } - - if ($this->ReturnPath) { - $result .= $this->HeaderLine('Return-Path', trim($this->ReturnPath)); - } elseif ($this->Sender == '') { - $result .= $this->HeaderLine('Return-Path', trim($this->From)); - } else { - $result .= $this->HeaderLine('Return-Path', trim($this->Sender)); - } - - // To be created automatically by mail() - if($this->Mailer != 'mail') { - if ($this->SingleTo === true) { - foreach($this->to as $t) { - $this->SingleToArray[] = $this->AddrFormat($t); - } - } else { - if(count($this->to) > 0) { - $result .= $this->AddrAppend('To', $this->to); - } elseif (count($this->cc) == 0) { - $result .= $this->HeaderLine('To', 'undisclosed-recipients:;'); - } - } - } - - $from = array(); - $from[0][0] = trim($this->From); - $from[0][1] = $this->FromName; - $result .= $this->AddrAppend('From', $from); - - // sendmail and mail() extract Cc from the header before sending - if(count($this->cc) > 0) { - $result .= $this->AddrAppend('Cc', $this->cc); - } - - // sendmail and mail() extract Bcc from the header before sending - if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) { - $result .= $this->AddrAppend('Bcc', $this->bcc); - } - - if(count($this->ReplyTo) > 0) { - $result .= $this->AddrAppend('Reply-To', $this->ReplyTo); - } - - // mail() sets the subject itself - if($this->Mailer != 'mail') { - $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject))); - } - - if($this->MessageID != '') { - $result .= $this->HeaderLine('Message-ID', $this->MessageID); - } else { - $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE); - } - $result .= $this->HeaderLine('X-Priority', $this->Priority); - if ($this->XMailer == '') { - $result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (http://code.google.com/a/apache-extras.org/p/phpmailer/)'); - } else { - $myXmailer = trim($this->XMailer); - if ($myXmailer) { - $result .= $this->HeaderLine('X-Mailer', $myXmailer); - } - } - - if($this->ConfirmReadingTo != '') { - $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>'); - } - - // Add custom headers - for($index = 0; $index < count($this->CustomHeader); $index++) { - $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1]))); - } - if (!$this->sign_key_file) { - $result .= $this->HeaderLine('MIME-Version', '1.0'); - $result .= $this->GetMailMIME(); - } - - return $result; - } - - /** - * Returns the message MIME. - * @access public - * @return string - */ - public function GetMailMIME() { - $result = ''; - switch($this->message_type) { - case 'inline': - $result .= $this->HeaderLine('Content-Type', 'multipart/related;'); - $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); - break; - case 'attach': - case 'inline_attach': - case 'alt_attach': - case 'alt_inline_attach': - $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;'); - $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); - break; - case 'alt': - case 'alt_inline': - $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;'); - $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); - break; - default: - // Catches case 'plain': and case '': - $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding); - $result .= $this->TextLine('Content-Type: '.$this->ContentType.'; charset='.$this->CharSet); - break; - } - - if($this->Mailer != 'mail') { - $result .= $this->LE; - } - - return $result; - } - - /** - * Returns the MIME message (headers and body). Only really valid post PreSend(). - * @access public - * @return string - */ - public function GetSentMIMEMessage() { - return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody; - } - - - /** - * Assembles the message body. Returns an empty string on failure. - * @access public - * @throws phpmailerException - * @return string The assembled message body - */ - public function CreateBody() { - $body = ''; - - if ($this->sign_key_file) { - $body .= $this->GetMailMIME().$this->LE; - } - - $this->SetWordWrap(); - - switch($this->message_type) { - case 'inline': - $body .= $this->GetBoundary($this->boundary[1], '', '', ''); - $body .= $this->EncodeString($this->Body, $this->Encoding); - $body .= $this->LE.$this->LE; - $body .= $this->AttachAll("inline", $this->boundary[1]); - break; - case 'attach': - $body .= $this->GetBoundary($this->boundary[1], '', '', ''); - $body .= $this->EncodeString($this->Body, $this->Encoding); - $body .= $this->LE.$this->LE; - $body .= $this->AttachAll("attachment", $this->boundary[1]); - break; - case 'inline_attach': - $body .= $this->TextLine("--" . $this->boundary[1]); - $body .= $this->HeaderLine('Content-Type', 'multipart/related;'); - $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"'); - $body .= $this->LE; - $body .= $this->GetBoundary($this->boundary[2], '', '', ''); - $body .= $this->EncodeString($this->Body, $this->Encoding); - $body .= $this->LE.$this->LE; - $body .= $this->AttachAll("inline", $this->boundary[2]); - $body .= $this->LE; - $body .= $this->AttachAll("attachment", $this->boundary[1]); - break; - case 'alt': - $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', ''); - $body .= $this->EncodeString($this->AltBody, $this->Encoding); - $body .= $this->LE.$this->LE; - $body .= $this->GetBoundary($this->boundary[1], '', 'text/html', ''); - $body .= $this->EncodeString($this->Body, $this->Encoding); - $body .= $this->LE.$this->LE; - $body .= $this->EndBoundary($this->boundary[1]); - break; - case 'alt_inline': - $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', ''); - $body .= $this->EncodeString($this->AltBody, $this->Encoding); - $body .= $this->LE.$this->LE; - $body .= $this->TextLine("--" . $this->boundary[1]); - $body .= $this->HeaderLine('Content-Type', 'multipart/related;'); - $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"'); - $body .= $this->LE; - $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', ''); - $body .= $this->EncodeString($this->Body, $this->Encoding); - $body .= $this->LE.$this->LE; - $body .= $this->AttachAll("inline", $this->boundary[2]); - $body .= $this->LE; - $body .= $this->EndBoundary($this->boundary[1]); - break; - case 'alt_attach': - $body .= $this->TextLine("--" . $this->boundary[1]); - $body .= $this->HeaderLine('Content-Type', 'multipart/alternative;'); - $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"'); - $body .= $this->LE; - $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', ''); - $body .= $this->EncodeString($this->AltBody, $this->Encoding); - $body .= $this->LE.$this->LE; - $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', ''); - $body .= $this->EncodeString($this->Body, $this->Encoding); - $body .= $this->LE.$this->LE; - $body .= $this->EndBoundary($this->boundary[2]); - $body .= $this->LE; - $body .= $this->AttachAll("attachment", $this->boundary[1]); - break; - case 'alt_inline_attach': - $body .= $this->TextLine("--" . $this->boundary[1]); - $body .= $this->HeaderLine('Content-Type', 'multipart/alternative;'); - $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"'); - $body .= $this->LE; - $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', ''); - $body .= $this->EncodeString($this->AltBody, $this->Encoding); - $body .= $this->LE.$this->LE; - $body .= $this->TextLine("--" . $this->boundary[2]); - $body .= $this->HeaderLine('Content-Type', 'multipart/related;'); - $body .= $this->TextLine("\tboundary=\"" . $this->boundary[3] . '"'); - $body .= $this->LE; - $body .= $this->GetBoundary($this->boundary[3], '', 'text/html', ''); - $body .= $this->EncodeString($this->Body, $this->Encoding); - $body .= $this->LE.$this->LE; - $body .= $this->AttachAll("inline", $this->boundary[3]); - $body .= $this->LE; - $body .= $this->EndBoundary($this->boundary[2]); - $body .= $this->LE; - $body .= $this->AttachAll("attachment", $this->boundary[1]); - break; - default: - // catch case 'plain' and case '' - $body .= $this->EncodeString($this->Body, $this->Encoding); - break; - } - - if ($this->IsError()) { - $body = ''; - } elseif ($this->sign_key_file) { - try { - $file = tempnam('', 'mail'); - file_put_contents($file, $body); //TODO check this worked - $signed = tempnam("", "signed"); - if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), NULL)) { - @unlink($file); - $body = file_get_contents($signed); - @unlink($signed); - } else { - @unlink($file); - @unlink($signed); - throw new phpmailerException($this->Lang("signing").openssl_error_string()); - } - } catch (phpmailerException $e) { - $body = ''; - if ($this->exceptions) { - throw $e; - } - } - } - - return $body; - } - - /** - * Returns the start of a message boundary. - * @access protected - * @param string $boundary - * @param string $charSet - * @param string $contentType - * @param string $encoding - * @return string - */ - protected function GetBoundary($boundary, $charSet, $contentType, $encoding) { - $result = ''; - if($charSet == '') { - $charSet = $this->CharSet; - } - if($contentType == '') { - $contentType = $this->ContentType; - } - if($encoding == '') { - $encoding = $this->Encoding; - } - $result .= $this->TextLine('--' . $boundary); - $result .= sprintf("Content-Type: %s; charset=%s", $contentType, $charSet); - $result .= $this->LE; - $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding); - $result .= $this->LE; - - return $result; - } - - /** - * Returns the end of a message boundary. - * @access protected - * @param string $boundary - * @return string - */ - protected function EndBoundary($boundary) { - return $this->LE . '--' . $boundary . '--' . $this->LE; - } - - /** - * Sets the message type. - * @access protected - * @return void - */ - protected function SetMessageType() { - $this->message_type = array(); - if($this->AlternativeExists()) $this->message_type[] = "alt"; - if($this->InlineImageExists()) $this->message_type[] = "inline"; - if($this->AttachmentExists()) $this->message_type[] = "attach"; - $this->message_type = implode("_", $this->message_type); - if($this->message_type == "") $this->message_type = "plain"; - } - - /** - * Returns a formatted header line. - * @access public - * @param string $name - * @param string $value - * @return string - */ - public function HeaderLine($name, $value) { - return $name . ': ' . $value . $this->LE; - } - - /** - * Returns a formatted mail line. - * @access public - * @param string $value - * @return string - */ - public function TextLine($value) { - return $value . $this->LE; - } - - ///////////////////////////////////////////////// - // CLASS METHODS, ATTACHMENTS - ///////////////////////////////////////////////// - - /** - * Adds an attachment from a path on the filesystem. - * Returns false if the file could not be found - * or accessed. - * @param string $path Path to the attachment. - * @param string $name Overrides the attachment name. - * @param string $encoding File encoding (see $Encoding). - * @param string $type File extension (MIME) type. - * @throws phpmailerException - * @return bool - */ - public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') { - try { - if ( !@is_file($path) ) { - throw new phpmailerException($this->Lang('file_access') . $path, self::STOP_CONTINUE); - } - $filename = basename($path); - if ( $name == '' ) { - $name = $filename; - } - - $this->attachment[] = array( - 0 => $path, - 1 => $filename, - 2 => $name, - 3 => $encoding, - 4 => $type, - 5 => false, // isStringAttachment - 6 => 'attachment', - 7 => 0 - ); - - } catch (phpmailerException $e) { - $this->SetError($e->getMessage()); - if ($this->exceptions) { - throw $e; - } - if ($this->SMTPDebug) { - $this->edebug($e->getMessage()."\n"); - } - if ( $e->getCode() == self::STOP_CRITICAL ) { - return false; - } - } - return true; - } - - /** - * Return the current array of attachments - * @return array - */ - public function GetAttachments() { - return $this->attachment; - } - - /** - * Attaches all fs, string, and binary attachments to the message. - * Returns an empty string on failure. - * @access protected - * @param string $disposition_type - * @param string $boundary - * @return string - */ - protected function AttachAll($disposition_type, $boundary) { - // Return text of body - $mime = array(); - $cidUniq = array(); - $incl = array(); - if(!class_exists('G')){ - $realdocuroot = str_replace( '\\', '/', $_SERVER['DOCUMENT_ROOT'] ); - $docuroot = explode( '/', $realdocuroot ); - array_pop( $docuroot ); - $pathhome = implode( '/', $docuroot ) . '/'; - array_pop( $docuroot ); - $pathTrunk = implode( '/', $docuroot ) . '/'; - require_once($pathTrunk.'gulliver/system/class.g.php'); - } - - // Add all attachments - foreach ($this->attachment as $attachment) { - // CHECK IF IT IS A VALID DISPOSITION_FILTER - if($attachment[6] == $disposition_type) { - // Check for string attachment - $string = ''; - $path = ''; - $bString = $attachment[5]; - if ($bString) { - $string = $attachment[0]; - } else { - $path = $attachment[0]; - } - - $inclhash = G::encryptOld(serialize($attachment)); - if (in_array($inclhash, $incl)) { continue; } - $incl[] = $inclhash; - $filename = $attachment[1]; - $name = $attachment[2]; - $encoding = $attachment[3]; - $type = $attachment[4]; - $disposition = $attachment[6]; - $cid = $attachment[7]; - if ( $disposition == 'inline' && isset($cidUniq[$cid]) ) { continue; } - $cidUniq[$cid] = true; - - $mime[] = sprintf("--%s%s", $boundary, $this->LE); - $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE); - $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE); - - if($disposition == 'inline') { - $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE); - } - - $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE); - - // Encode as string attachment - if($bString) { - $mime[] = $this->EncodeString($string, $encoding); - if($this->IsError()) { - return ''; - } - $mime[] = $this->LE.$this->LE; - } else { - $mime[] = $this->EncodeFile($path, $encoding); - if($this->IsError()) { - return ''; - } - $mime[] = $this->LE.$this->LE; - } - } - } - - $mime[] = sprintf("--%s--%s", $boundary, $this->LE); - - return implode("", $mime); - } - - /** - * Encodes attachment in requested format. - * Returns an empty string on failure. - * @param string $path The full path to the file - * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable' - * @throws phpmailerException - * @see EncodeFile() - * @access protected - * @return string - */ - protected function EncodeFile($path, $encoding = 'base64') { - try { - if (!is_readable($path)) { - throw new phpmailerException($this->Lang('file_open') . $path, self::STOP_CONTINUE); - } - // if (!function_exists('get_magic_quotes')) { - // function get_magic_quotes() { - // return false; - // } - // } - $magic_quotes = get_magic_quotes_runtime(); - if ($magic_quotes) { - if (version_compare(PHP_VERSION, '5.3.0', '<')) { - set_magic_quotes_runtime(0); - } else { - ini_set('magic_quotes_runtime', 0); - } - } - $file_buffer = file_get_contents($path); - $file_buffer = $this->EncodeString($file_buffer, $encoding); - if ($magic_quotes) { - if (version_compare(PHP_VERSION, '5.3.0', '<')) { - set_magic_quotes_runtime($magic_quotes); - } else { - ini_set('magic_quotes_runtime', $magic_quotes); - } - } - return $file_buffer; - } catch (Exception $e) { - $this->SetError($e->getMessage()); - return ''; - } - } - - /** - * Encodes string to requested format. - * Returns an empty string on failure. - * @param string $str The text to encode - * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable' - * @access public - * @return string - */ - public function EncodeString($str, $encoding = 'base64') { - $encoded = ''; - switch(strtolower($encoding)) { - case 'base64': - $encoded = chunk_split(base64_encode($str), 76, $this->LE); - break; - case '7bit': - case '8bit': - $encoded = $this->FixEOL($str); - //Make sure it ends with a line break - if (substr($encoded, -(strlen($this->LE))) != $this->LE) - $encoded .= $this->LE; - break; - case 'binary': - $encoded = $str; - break; - case 'quoted-printable': - $encoded = $this->EncodeQP($str); - break; - default: - $this->SetError($this->Lang('encoding') . $encoding); - break; - } - return $encoded; - } - - /** - * Encode a header string to best (shortest) of Q, B, quoted or none. - * @access public - * @param string $str - * @param string $position - * @return string - */ - public function EncodeHeader($str, $position = 'text') { - $x = 0; - - switch (strtolower($position)) { - case 'phrase': - if (!preg_match('/[\200-\377]/', $str)) { - // Can't use addslashes as we don't know what value has magic_quotes_sybase - $encoded = addcslashes($str, "\0..\37\177\\\""); - if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) { - return ($encoded); - } else { - return ("\"$encoded\""); - } - } - $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); - break; - case 'comment': - $x = preg_match_all('/[()"]/', $str, $matches); - // Fall-through - case 'text': - default: - $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); - break; - } - - if ($x == 0) { - return ($str); - } - - $maxlen = 75 - 7 - strlen($this->CharSet); - // Try to select the encoding which should produce the shortest output - if (strlen($str)/3 < $x) { - $encoding = 'B'; - if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) { - // Use a custom function which correctly encodes and wraps long - // multibyte strings without breaking lines within a character - $encoded = $this->Base64EncodeWrapMB($str, "\n"); - } else { - $encoded = base64_encode($str); - $maxlen -= $maxlen % 4; - $encoded = trim(chunk_split($encoded, $maxlen, "\n")); - } - } else { - $encoding = 'Q'; - $encoded = $this->EncodeQ($str, $position); - $encoded = $this->WrapText($encoded, $maxlen, true); - $encoded = str_replace('='.self::CRLF, "\n", trim($encoded)); - } - - $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded); - $encoded = trim(str_replace("\n", $this->LE, $encoded)); - - return $encoded; - } - - /** - * Checks if a string contains multibyte characters. - * @access public - * @param string $str multi-byte text to wrap encode - * @return bool - */ - public function HasMultiBytes($str) { - if (function_exists('mb_strlen')) { - return (strlen($str) > mb_strlen($str, $this->CharSet)); - } else { // Assume no multibytes (we can't handle without mbstring functions anyway) - return false; - } - } - - /** - * Correctly encodes and wraps long multibyte strings for mail headers - * without breaking lines within a character. - * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php - * @access public - * @param string $str multi-byte text to wrap encode - * @param string $lf string to use as linefeed/end-of-line - * @return string - */ - public function Base64EncodeWrapMB($str, $lf=null) { - $start = "=?".$this->CharSet."?B?"; - $end = "?="; - $encoded = ""; - if ($lf === null) { - $lf = $this->LE; - } - - $mb_length = mb_strlen($str, $this->CharSet); - // Each line must have length <= 75, including $start and $end - $length = 75 - strlen($start) - strlen($end); - // Average multi-byte ratio - $ratio = $mb_length / strlen($str); - // Base64 has a 4:3 ratio - $offset = $avgLength = floor($length * $ratio * .75); - - for ($i = 0; $i < $mb_length; $i += $offset) { - $lookBack = 0; - - do { - $offset = $avgLength - $lookBack; - $chunk = mb_substr($str, $i, $offset, $this->CharSet); - $chunk = base64_encode($chunk); - $lookBack++; - } - while (strlen($chunk) > $length); - - $encoded .= $chunk . $lf; - } - - // Chomp the last linefeed - $encoded = substr($encoded, 0, -strlen($lf)); - return $encoded; - } - - /** - * Encode string to quoted-printable. - * Only uses standard PHP, slow, but will always work - * @access public - * @param string $input - * @param integer $line_max Number of chars allowed on a line before wrapping - * @param bool $space_conv - * @internal param string $string the text to encode - * @return string - */ - public function EncodeQPphp( $input = '', $line_max = 76, $space_conv = false) { - $hex = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); - $lines = preg_split('/(?:\r\n|\r|\n)/', $input); - $eol = "\r\n"; - $escape = '='; - $output = ''; - while( list(, $line) = each($lines) ) { - $linlen = strlen($line); - $newline = ''; - for($i = 0; $i < $linlen; $i++) { - $c = substr( $line, $i, 1 ); - $dec = ord( $c ); - if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E - $c = '=2E'; - } - if ( $dec == 32 ) { - if ( $i == ( $linlen - 1 ) ) { // convert space at eol only - $c = '=20'; - } else if ( $space_conv ) { - $c = '=20'; - } - } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required - $h2 = (integer)floor($dec/16); - $h1 = (integer)floor($dec%16); - $c = $escape.$hex[$h2].$hex[$h1]; - } - if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted - $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay - $newline = ''; - // check if newline first character will be point or not - if ( $dec == 46 ) { - $c = '=2E'; - } - } - $newline .= $c; - } // end of for - $output .= $newline.$eol; - } // end of while - return $output; - } - - /** - * Encode string to RFC2045 (6.7) quoted-printable format - * Uses a PHP5 stream filter to do the encoding about 64x faster than the old version - * Also results in same content as you started with after decoding - * @see EncodeQPphp() - * @access public - * @param string $string the text to encode - * @param integer $line_max Number of chars allowed on a line before wrapping - * @param boolean $space_conv Dummy param for compatibility with existing EncodeQP function - * @return string - * @author Marcus Bointon - */ - public function EncodeQP($string, $line_max = 76, $space_conv = false) { - if (function_exists('quoted_printable_encode')) { //Use native function if it's available (>= PHP5.3) - return quoted_printable_encode($string); - } - $filters = stream_get_filters(); - if (!in_array('convert.*', $filters)) { //Got convert stream filter? - return $this->EncodeQPphp($string, $line_max, $space_conv); //Fall back to old implementation - } - $fp = fopen('php://temp/', 'r+'); - $string = preg_replace('/\r\n?/', $this->LE, $string); //Normalise line breaks - $params = array('line-length' => $line_max, 'line-break-chars' => $this->LE); - $s = stream_filter_append($fp, 'convert.quoted-printable-encode', STREAM_FILTER_READ, $params); - fputs($fp, $string); - rewind($fp); - $out = stream_get_contents($fp); - stream_filter_remove($s); - $out = preg_replace('/^\./m', '=2E', $out); //Encode . if it is first char on a line, workaround for bug in Exchange - fclose($fp); - return $out; - } - - /** - * Encode string to q encoding. - * @link http://tools.ietf.org/html/rfc2047 - * @param string $str the text to encode - * @param string $position Where the text is going to be used, see the RFC for what that means - * @access public - * @return string - */ - public function EncodeQ($str, $position = 'text') { - //There should not be any EOL in the string - $pattern=""; - $encoded = str_replace(array("\r", "\n"), '', $str); - switch (strtolower($position)) { - case 'phrase': - $pattern = '^A-Za-z0-9!*+\/ -'; - break; - - case 'comment': - $pattern = '\(\)"'; - //note that we dont break here! - //for this reason we build the $pattern withoud including delimiters and [] - - case 'text': - default: - //Replace every high ascii, control =, ? and _ characters - //We put \075 (=) as first value to make sure it's the first one in being converted, preventing double encode - $pattern = '\075\000-\011\013\014\016-\037\077\137\177-\377' . $pattern; - break; - } - - if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) { - foreach (array_unique($matches[0]) as $char) { - $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded); - } - } - - //Replace every spaces to _ (more readable than =20) - return str_replace(' ', '_', $encoded); -} - - - /** - * Adds a string or binary attachment (non-filesystem) to the list. - * This method can be used to attach ascii or binary data, - * such as a BLOB record from a database. - * @param string $string String attachment data. - * @param string $filename Name of the attachment. - * @param string $encoding File encoding (see $Encoding). - * @param string $type File extension (MIME) type. - * @return void - */ - public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') { - // Append to $attachment array - $this->attachment[] = array( - 0 => $string, - 1 => $filename, - 2 => basename($filename), - 3 => $encoding, - 4 => $type, - 5 => true, // isStringAttachment - 6 => 'attachment', - 7 => 0 - ); - } - - /** - * Adds an embedded attachment. This can include images, sounds, and - * just about any other document. Make sure to set the $type to an - * image type. For JPEG images use "image/jpeg" and for GIF images - * use "image/gif". - * @param string $path Path to the attachment. - * @param string $cid Content ID of the attachment. Use this to identify - * the Id for accessing the image in an HTML form. - * @param string $name Overrides the attachment name. - * @param string $encoding File encoding (see $Encoding). - * @param string $type File extension (MIME) type. - * @return bool - */ - public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') { - - if ( !@is_file($path) ) { - $this->SetError($this->Lang('file_access') . $path); - return false; - } - - $filename = basename($path); - if ( $name == '' ) { - $name = $filename; - } - - // Append to $attachment array - $this->attachment[] = array( - 0 => $path, - 1 => $filename, - 2 => $name, - 3 => $encoding, - 4 => $type, - 5 => false, // isStringAttachment - 6 => 'inline', - 7 => $cid - ); - - return true; - } - - /** - * Adds an embedded stringified attachment. This can include images, sounds, and - * just about any other document. Make sure to set the $type to an - * image type. For JPEG images use "image/jpeg" and for GIF images - * use "image/gif". - * @param string $string The attachment. - * @param string $cid Content ID of the attachment. Use this to identify - * the Id for accessing the image in an HTML form. - * @param string $name Overrides the attachment name. - * @param string $encoding File encoding (see $Encoding). - * @param string $type File extension (MIME) type. - * @return bool - */ - public function AddStringEmbeddedImage($string, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') { - // Append to $attachment array - $this->attachment[] = array( - 0 => $string, - 1 => $name, - 2 => $name, - 3 => $encoding, - 4 => $type, - 5 => true, // isStringAttachment - 6 => 'inline', - 7 => $cid - ); - } - - /** - * Returns true if an inline attachment is present. - * @access public - * @return bool - */ - public function InlineImageExists() { - foreach($this->attachment as $attachment) { - if ($attachment[6] == 'inline') { - return true; - } - } - return false; - } - - /** - * Returns true if an attachment (non-inline) is present. - * @return bool - */ - public function AttachmentExists() { - foreach($this->attachment as $attachment) { - if ($attachment[6] == 'attachment') { - return true; - } - } - return false; - } - - /** - * Does this message have an alternative body set? - * @return bool - */ - public function AlternativeExists() { - return !empty($this->AltBody); - } - - ///////////////////////////////////////////////// - // CLASS METHODS, MESSAGE RESET - ///////////////////////////////////////////////// - - /** - * Clears all recipients assigned in the TO array. Returns void. - * @return void - */ - public function ClearAddresses() { - foreach($this->to as $to) { - unset($this->all_recipients[strtolower($to[0])]); - } - $this->to = array(); - } - - /** - * Clears all recipients assigned in the CC array. Returns void. - * @return void - */ - public function ClearCCs() { - foreach($this->cc as $cc) { - unset($this->all_recipients[strtolower($cc[0])]); - } - $this->cc = array(); - } - - /** - * Clears all recipients assigned in the BCC array. Returns void. - * @return void - */ - public function ClearBCCs() { - foreach($this->bcc as $bcc) { - unset($this->all_recipients[strtolower($bcc[0])]); - } - $this->bcc = array(); - } - - /** - * Clears all recipients assigned in the ReplyTo array. Returns void. - * @return void - */ - public function ClearReplyTos() { - $this->ReplyTo = array(); - } - - /** - * Clears all recipients assigned in the TO, CC and BCC - * array. Returns void. - * @return void - */ - public function ClearAllRecipients() { - $this->to = array(); - $this->cc = array(); - $this->bcc = array(); - $this->all_recipients = array(); - } - - /** - * Clears all previously set filesystem, string, and binary - * attachments. Returns void. - * @return void - */ - public function ClearAttachments() { - $this->attachment = array(); - } - - /** - * Clears all custom headers. Returns void. - * @return void - */ - public function ClearCustomHeaders() { - $this->CustomHeader = array(); - } - - ///////////////////////////////////////////////// - // CLASS METHODS, MISCELLANEOUS - ///////////////////////////////////////////////// - - /** - * Adds the error message to the error container. - * @access protected - * @param string $msg - * @return void - */ - protected function SetError($msg) { - $this->error_count++; - if ($this->Mailer == 'smtp' and !is_null($this->smtp)) { - $lasterror = $this->smtp->getError(); - if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) { - $msg .= '

' . $this->Lang('smtp_error') . $lasterror['smtp_msg'] . "

\n"; - } - } - $this->ErrorInfo = $msg; - } - - /** - * Returns the proper RFC 822 formatted date. - * @access public - * @return string - * @static - */ - public static function RFCDate() { - $tz = date('Z'); - $tzs = ($tz < 0) ? '-' : '+'; - $tz = abs($tz); - $tz = (int)($tz/3600)*100 + ($tz%3600)/60; - $result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz); - - return $result; - } - - /** - * Returns the server hostname or 'localhost.localdomain' if unknown. - * @access protected - * @return string - */ - protected function ServerHostname() { - if (!empty($this->Hostname)) { - $result = $this->Hostname; - } elseif (isset($_SERVER['SERVER_NAME'])) { - $result = $_SERVER['SERVER_NAME']; - } else { - $result = 'localhost.localdomain'; - } - - return $result; - } - - /** - * Returns a message in the appropriate language. - * @access protected - * @param string $key - * @return string - */ - protected function Lang($key) { - $lang = 'en'; - if(count($this->language) < 1) { - if (defined('SYS_LANG')) { - $lang = SYS_LANG; - } - $this->SetLanguage($lang); - } - - if(isset($this->language[$key])) { - return $this->language[$key]; - } else { - return 'Language string failed to load: ' . $key; - } - } - - /** - * Returns true if an error occurred. - * @access public - * @return bool - */ - public function IsError() { - return ($this->error_count > 0); - } - - /** - * Changes every end of line from CRLF, CR or LF to $this->LE. - * @access public - * @param string $str String to FixEOL - * @return string - */ - public function FixEOL($str) { - // condense down to \n - $nstr = str_replace(array("\r\n", "\r"), "\n", $str); - // Now convert LE as needed - if ($this->LE !== "\n") { - $nstr = str_replace("\n", $this->LE, $nstr); - } - return $nstr; - } - - /** - * Adds a custom header. $name value can be overloaded to contain - * both header name and value (name:value) - * @access public - * @param string $name custom header name - * @param string $value header value - * @return void - */ - public function AddCustomHeader($name, $value=null) { - if ($value === null) { - // Value passed in as name:value - $this->CustomHeader[] = explode(':', $name, 2); - } else { - $this->CustomHeader[] = array($name, $value); - } - } - - /** - * Evaluates the message and returns modifications for inline images and backgrounds - * @access public - * @param string $message Text to be HTML modified - * @param string $basedir baseline directory for path - * @return string $message - */ - public function MsgHTML($message, $basedir = '') { - preg_match_all("/(src|background)=[\"'](.*)[\"']/Ui", $message, $images); - if(!class_exists('G')){ - $realdocuroot = str_replace( '\\', '/', $_SERVER['DOCUMENT_ROOT'] ); - $docuroot = explode( '/', $realdocuroot ); - array_pop( $docuroot ); - $pathhome = implode( '/', $docuroot ) . '/'; - array_pop( $docuroot ); - $pathTrunk = implode( '/', $docuroot ) . '/'; - require_once($pathTrunk.'gulliver/system/class.g.php'); - } - if(isset($images[2])) { - foreach($images[2] as $i => $url) { - // do not change urls for absolute images (thanks to corvuscorax) - if (!preg_match('#^[A-z]+://#', $url)) { - $filename = basename($url); - $directory = dirname($url); - if ($directory == '.') { - $directory = ''; - } - $cid = 'cid:' . G::encryptOld($url); - $ext = pathinfo($filename, PATHINFO_EXTENSION); - $mimeType = self::_mime_types($ext); - if ( strlen($basedir) > 1 && substr($basedir, -1) != '/') { $basedir .= '/'; } - if ( strlen($directory) > 1 && substr($directory, -1) != '/') { $directory .= '/'; } - if ( $this->AddEmbeddedImage($basedir.$directory.$filename, G::encryptOld($url), $filename, 'base64', $mimeType) ) { - $message = preg_replace("/".$images[1][$i]."=[\"']".preg_quote($url, '/')."[\"']/Ui", $images[1][$i]."=\"".$cid."\"", $message); - } - } - } - } - $this->IsHTML(true); - $this->Body = $message; - if (empty($this->AltBody)) { - $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s', '', $message))); - if (!empty($textMsg)) { - $this->AltBody = html_entity_decode($textMsg, ENT_QUOTES, $this->CharSet); - } - } - if (empty($this->AltBody)) { - $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . "\n\n"; - } - return $message; - } - - /** - * Gets the MIME type of the embedded or inline image - * @param string $ext File extension - * @access public - * @return string MIME type of ext - * @static - */ - public static function _mime_types($ext = '') { - $mimes = array( - 'xl' => 'application/excel', - 'hqx' => 'application/mac-binhex40', - 'cpt' => 'application/mac-compactpro', - 'bin' => 'application/macbinary', - 'doc' => 'application/msword', - 'word' => 'application/msword', - 'class' => 'application/octet-stream', - 'dll' => 'application/octet-stream', - 'dms' => 'application/octet-stream', - 'exe' => 'application/octet-stream', - 'lha' => 'application/octet-stream', - 'lzh' => 'application/octet-stream', - 'psd' => 'application/octet-stream', - 'sea' => 'application/octet-stream', - 'so' => 'application/octet-stream', - 'oda' => 'application/oda', - 'pdf' => 'application/pdf', - 'ai' => 'application/postscript', - 'eps' => 'application/postscript', - 'ps' => 'application/postscript', - 'smi' => 'application/smil', - 'smil' => 'application/smil', - 'mif' => 'application/vnd.mif', - 'xls' => 'application/vnd.ms-excel', - 'ppt' => 'application/vnd.ms-powerpoint', - 'wbxml' => 'application/vnd.wap.wbxml', - 'wmlc' => 'application/vnd.wap.wmlc', - 'dcr' => 'application/x-director', - 'dir' => 'application/x-director', - 'dxr' => 'application/x-director', - 'dvi' => 'application/x-dvi', - 'gtar' => 'application/x-gtar', - 'php3' => 'application/x-httpd-php', - 'php4' => 'application/x-httpd-php', - 'php' => 'application/x-httpd-php', - 'phtml' => 'application/x-httpd-php', - 'phps' => 'application/x-httpd-php-source', - 'js' => 'application/x-javascript', - 'swf' => 'application/x-shockwave-flash', - 'sit' => 'application/x-stuffit', - 'tar' => 'application/x-tar', - 'tgz' => 'application/x-tar', - 'xht' => 'application/xhtml+xml', - 'xhtml' => 'application/xhtml+xml', - 'zip' => 'application/zip', - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', - 'mp2' => 'audio/mpeg', - 'mp3' => 'audio/mpeg', - 'mpga' => 'audio/mpeg', - 'aif' => 'audio/x-aiff', - 'aifc' => 'audio/x-aiff', - 'aiff' => 'audio/x-aiff', - 'ram' => 'audio/x-pn-realaudio', - 'rm' => 'audio/x-pn-realaudio', - 'rpm' => 'audio/x-pn-realaudio-plugin', - 'ra' => 'audio/x-realaudio', - 'wav' => 'audio/x-wav', - 'bmp' => 'image/bmp', - 'gif' => 'image/gif', - 'jpeg' => 'image/jpeg', - 'jpe' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'png' => 'image/png', - 'tiff' => 'image/tiff', - 'tif' => 'image/tiff', - 'eml' => 'message/rfc822', - 'css' => 'text/css', - 'html' => 'text/html', - 'htm' => 'text/html', - 'shtml' => 'text/html', - 'log' => 'text/plain', - 'text' => 'text/plain', - 'txt' => 'text/plain', - 'rtx' => 'text/richtext', - 'rtf' => 'text/rtf', - 'xml' => 'text/xml', - 'xsl' => 'text/xml', - 'mpeg' => 'video/mpeg', - 'mpe' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'mov' => 'video/quicktime', - 'qt' => 'video/quicktime', - 'rv' => 'video/vnd.rn-realvideo', - 'avi' => 'video/x-msvideo', - 'movie' => 'video/x-sgi-movie' - ); - return (!isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)]; - } - - /** - * Set (or reset) Class Objects (variables) - * - * Usage Example: - * $page->set('X-Priority', '3'); - * - * @access public - * @param string $name Parameter Name - * @param mixed $value Parameter Value - * NOTE: will not work with arrays, there are no arrays to set/reset - * @throws phpmailerException - * @return bool - * @todo Should this not be using __set() magic function? - */ - public function set($name, $value = '') { - try { - if (isset($this->$name) ) { - $this->$name = $value; - } else { - throw new phpmailerException($this->Lang('variable_set') . $name, self::STOP_CRITICAL); - } - } catch (Exception $e) { - $this->SetError($e->getMessage()); - if ($e->getCode() == self::STOP_CRITICAL) { - return false; - } - } - return true; - } - - /** - * Strips newlines to prevent header injection. - * @access public - * @param string $str String - * @return string - */ - public function SecureHeader($str) { - return trim(str_replace(array("\r", "\n"), '', $str)); - } - - /** - * Set the private key file and password to sign the message. - * - * @access public - * @param $cert_filename - * @param string $key_filename Parameter File Name - * @param string $key_pass Password for private key - */ - public function Sign($cert_filename, $key_filename, $key_pass) { - $this->sign_cert_file = $cert_filename; - $this->sign_key_file = $key_filename; - $this->sign_key_pass = $key_pass; - } - - /** - * Set the private key file and password to sign the message. - * - * @access public - * @param string $txt - * @return string - */ - public function DKIM_QP($txt) { - $line = ''; - for ($i = 0; $i < strlen($txt); $i++) { - $ord = ord($txt[$i]); - if ( ((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E)) ) { - $line .= $txt[$i]; - } else { - $line .= "=".sprintf("%02X", $ord); - } - } - return $line; - } - - /** - * Generate DKIM signature - * - * @access public - * @param string $s Header - * @return string - */ - public function DKIM_Sign($s) { - $privKeyStr = file_get_contents($this->DKIM_private); - if ($this->DKIM_passphrase != '') { - $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase); - } else { - $privKey = $privKeyStr; - } - if (openssl_sign($s, $signature, $privKey)) { - return base64_encode($signature); - } - return ''; - } - - /** - * Generate DKIM Canonicalization Header - * - * @access public - * @param string $s Header - * @return string - */ - public function DKIM_HeaderC($s) { - $s = preg_replace("/\r\n\s+/", " ", $s); - $lines = explode("\r\n", $s); - foreach ($lines as $key => $line) { - list($heading, $value) = explode(":", $line, 2); - $heading = strtolower($heading); - $value = preg_replace("/\s+/", " ", $value) ; // Compress useless spaces - $lines[$key] = $heading.":".trim($value) ; // Don't forget to remove WSP around the value - } - $s = implode("\r\n", $lines); - return $s; - } - - /** - * Generate DKIM Canonicalization Body - * - * @access public - * @param string $body Message Body - * @return string - */ - public function DKIM_BodyC($body) { - if ($body == '') return "\r\n"; - // stabilize line endings - $body = str_replace("\r\n", "\n", $body); - $body = str_replace("\n", "\r\n", $body); - // END stabilize line endings - while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") { - $body = substr($body, 0, strlen($body) - 2); - } - return $body; - } - - /** - * Create the DKIM header, body, as new header - * - * @access public - * @param string $headers_line Header lines - * @param string $subject Subject - * @param string $body Body - * @return string - */ - public function DKIM_Add($headers_line, $subject, $body) { - $DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms - $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body - $DKIMquery = 'dns/txt'; // Query method - $DKIMtime = time() ; // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone) - $subject_header = "Subject: $subject"; - $headers = explode($this->LE, $headers_line); - $from_header = ""; - $to_header = ""; - foreach($headers as $header) { - if (strpos($header, 'From:') === 0) { - $from_header = $header; - } elseif (strpos($header, 'To:') === 0) { - $to_header = $header; - } - } - $from = str_replace('|', '=7C', $this->DKIM_QP($from_header)); - $to = str_replace('|', '=7C', $this->DKIM_QP($to_header)); - $subject = str_replace('|', '=7C', $this->DKIM_QP($subject_header)) ; // Copied header fields (dkim-quoted-printable - $body = $this->DKIM_BodyC($body); - $DKIMlen = strlen($body) ; // Length of body - $DKIMb64 = base64_encode(pack("H*", sha1($body))) ; // Base64 of packed binary SHA-1 hash of body - $ident = ($this->DKIM_identity == '')? '' : " i=" . $this->DKIM_identity . ";"; - $dkimhdrs = "DKIM-Signature: v=1; a=" . $DKIMsignatureType . "; q=" . $DKIMquery . "; l=" . $DKIMlen . "; s=" . $this->DKIM_selector . ";\r\n". - "\tt=" . $DKIMtime . "; c=" . $DKIMcanonicalization . ";\r\n". - "\th=From:To:Subject;\r\n". - "\td=" . $this->DKIM_domain . ";" . $ident . "\r\n". - "\tz=$from\r\n". - "\t|$to\r\n". - "\t|$subject;\r\n". - "\tbh=" . $DKIMb64 . ";\r\n". - "\tb="; - $toSign = $this->DKIM_HeaderC($from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs); - $signed = $this->DKIM_Sign($toSign); - return "X-PHPMAILER-DKIM: code.google.com/a/apache-extras.org/p/phpmailer/\r\n".$dkimhdrs.$signed."\r\n"; - } - - /** - * Perform callback - * @param boolean $isSent - * @param string $to - * @param string $cc - * @param string $bcc - * @param string $subject - * @param string $body - * @param string $from - */ - protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from=null) { - if (!empty($this->action_function) && is_callable($this->action_function)) { - $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from); - call_user_func_array($this->action_function, $params); - } - } -} - -/** - * Exception handler for PHPMailer - * @package PHPMailer - */ -class phpmailerException extends Exception { - /** - * Prettify error message output - * @return string - */ - public function errorMessage() { - $errorMsg = '' . $this->getMessage() . "
\n"; - return $errorMsg; - } -} -?> diff --git a/thirdparty/phpmailer/class.pop3.php b/thirdparty/phpmailer/class.pop3.php deleted file mode 100644 index 506b59994..000000000 --- a/thirdparty/phpmailer/class.pop3.php +++ /dev/null @@ -1,418 +0,0 @@ - - * @author Andy Prevost - * @author Jim Jagielski - */ - -class POP3 { - /** - * Default POP3 port - * @var int - */ - public $POP3_PORT = 110; - - /** - * Default Timeout - * @var int - */ - public $POP3_TIMEOUT = 30; - - /** - * POP3 Carriage Return + Line Feed - * @var string - */ - public $CRLF = "\r\n"; - - /** - * Displaying Debug warnings? (0 = now, 1+ = yes) - * @var int - */ - public $do_debug = 2; - - /** - * POP3 Mail Server - * @var string - */ - public $host; - - /** - * POP3 Port - * @var int - */ - public $port; - - /** - * POP3 Timeout Value - * @var int - */ - public $tval; - - /** - * POP3 Username - * @var string - */ - public $username; - - /** - * POP3 Password - * @var string - */ - public $password; - - /** - * Sets the POP3 PHPMailer Version number - * @var string - */ - public $Version = '5.2.4'; - - ///////////////////////////////////////////////// - // PROPERTIES, PRIVATE AND PROTECTED - ///////////////////////////////////////////////// - - /** - * @var resource Resource handle for the POP connection socket - */ - private $pop_conn; - /** - * @var boolean Are we connected? - */ - private $connected; - /** - * @var array Error container - */ - private $error; // Error log array - - /** - * Constructor, sets the initial values - * @access public - * @return POP3 - */ - public function __construct() { - $this->pop_conn = 0; - $this->connected = false; - $this->error = null; - } - - /** - * Combination of public events - connect, login, disconnect - * @access public - * @param string $host - * @param bool|int $port - * @param bool|int $tval - * @param string $username - * @param string $password - * @param int $debug_level - * @return bool - */ - public function Authorise ($host, $port = false, $tval = false, $username, $password, $debug_level = 0) { - $this->host = $host; - - // If no port value is passed, retrieve it - if ($port == false) { - $this->port = $this->POP3_PORT; - } else { - $this->port = $port; - } - - // If no port value is passed, retrieve it - if ($tval == false) { - $this->tval = $this->POP3_TIMEOUT; - } else { - $this->tval = $tval; - } - - $this->do_debug = $debug_level; - $this->username = $username; - $this->password = $password; - - // Refresh the error log - $this->error = null; - - // Connect - $result = $this->Connect($this->host, $this->port, $this->tval); - - if ($result) { - $login_result = $this->Login($this->username, $this->password); - - if ($login_result) { - $this->Disconnect(); - - return true; - } - - } - - // We need to disconnect regardless if the login succeeded - $this->Disconnect(); - - return false; - } - - /** - * Connect to the POP3 server - * @access public - * @param string $host - * @param bool|int $port - * @param integer $tval - * @return boolean - */ - public function Connect ($host, $port = false, $tval = 30) { - // Are we already connected? - if ($this->connected) { - return true; - } - - /* - On Windows this will raise a PHP Warning error if the hostname doesn't exist. - Rather than supress it with @fsockopen, let's capture it cleanly instead - */ - - set_error_handler(array(&$this, 'catchWarning')); - - // Connect to the POP3 server - $this->pop_conn = fsockopen($host, // POP3 Host - $port, // Port # - $errno, // Error Number - $errstr, // Error Message - $tval); // Timeout (seconds) - - // Restore the error handler - restore_error_handler(); - - // Does the Error Log now contain anything? - if ($this->error && $this->do_debug >= 1) { - $this->displayErrors(); - } - - // Did we connect? - if ($this->pop_conn == false) { - // It would appear not... - $this->error = array( - 'error' => "Failed to connect to server $host on port $port", - 'errno' => $errno, - 'errstr' => $errstr - ); - - if ($this->do_debug >= 1) { - $this->displayErrors(); - } - - return false; - } - - // Increase the stream time-out - - // Check for PHP 4.3.0 or later - if (version_compare(phpversion(), '5.0.0', 'ge')) { - stream_set_timeout($this->pop_conn, $tval, 0); - } else { - // Does not work on Windows - if (substr(PHP_OS, 0, 3) !== 'WIN') { - socket_set_timeout($this->pop_conn, $tval, 0); - } - } - - // Get the POP3 server response - $pop3_response = $this->getResponse(); - - // Check for the +OK - if ($this->checkResponse($pop3_response)) { - // The connection is established and the POP3 server is talking - $this->connected = true; - return true; - } - return false; - } - - /** - * Login to the POP3 server (does not support APOP yet) - * @access public - * @param string $username - * @param string $password - * @return boolean - */ - public function Login ($username = '', $password = '') { - if ($this->connected == false) { - $this->error = 'Not connected to POP3 server'; - - if ($this->do_debug >= 1) { - $this->displayErrors(); - } - } - - if (empty($username)) { - $username = $this->username; - } - - if (empty($password)) { - $password = $this->password; - } - - $pop_username = "USER $username" . $this->CRLF; - $pop_password = "PASS $password" . $this->CRLF; - - // Send the Username - $this->sendString($pop_username); - $pop3_response = $this->getResponse(); - - if ($this->checkResponse($pop3_response)) { - // Send the Password - $this->sendString($pop_password); - $pop3_response = $this->getResponse(); - - if ($this->checkResponse($pop3_response)) { - return true; - } - } - return false; - } - - /** - * Disconnect from the POP3 server - * @access public - */ - public function Disconnect () { - $this->sendString('QUIT'); - - fclose($this->pop_conn); - } - - ///////////////////////////////////////////////// - // Private Methods - ///////////////////////////////////////////////// - - /** - * Get the socket response back. - * $size is the maximum number of bytes to retrieve - * @access private - * @param integer $size - * @return string - */ - private function getResponse ($size = 128) { - $pop3_response = fgets($this->pop_conn, $size); - - return $pop3_response; - } - - /** - * Send a string down the open socket connection to the POP3 server - * @access private - * @param string $string - * @return integer - */ - private function sendString ($string) { - $bytes_sent = fwrite($this->pop_conn, $string, strlen($string)); - - return $bytes_sent; - } - - /** - * Checks the POP3 server response for +OK or -ERR - * @access private - * @param string $string - * @return boolean - */ - private function checkResponse ($string) { - if (substr($string, 0, 3) !== '+OK') { - $this->error = array( - 'error' => "Server reported an error: $string", - 'errno' => 0, - 'errstr' => '' - ); - - if ($this->do_debug >= 1) { - $this->displayErrors(); - } - - return false; - } else { - return true; - } - - } - - /** - * If debug is enabled, display the error message array - * @access private - */ - private function displayErrors () { - echo '
';
-
-    foreach ($this->error as $single_error) {
-      print_r($single_error);
-    }
-
-    echo '
'; - } - - /** - * Takes over from PHP for the socket warning handler - * @access private - * @param integer $errno - * @param string $errstr - * @param string $errfile - * @param integer $errline - */ - private function catchWarning ($errno, $errstr, $errfile, $errline) { - $this->error[] = array( - 'error' => "Connecting to the POP3 server raised a PHP warning: ", - 'errno' => $errno, - 'errstr' => $errstr - ); - } - - // End of class -} -?> diff --git a/thirdparty/phpmailer/class.smtp.php b/thirdparty/phpmailer/class.smtp.php deleted file mode 100644 index 45abc8694..000000000 --- a/thirdparty/phpmailer/class.smtp.php +++ /dev/null @@ -1,1002 +0,0 @@ -Debugoutput == "error_log") { - error_log($str); - } else { - echo $str; - } - } - - /** - * Initialize the class so that the data is in a known state. - * @access public - * @return SMTP - */ - public function __construct() { - $this->smtp_conn = 0; - $this->error = null; - $this->helo_rply = null; - - $this->do_debug = 0; - } - - ///////////////////////////////////////////////// - // CONNECTION FUNCTIONS - ///////////////////////////////////////////////// - - /** - * Connect to the server specified on the port specified. - * If the port is not specified use the default SMTP_PORT. - * If tval is specified then a connection will try and be - * established with the server for that number of seconds. - * If tval is not specified the default is 30 seconds to - * try on the connection. - * - * SMTP CODE SUCCESS: 220 - * SMTP CODE FAILURE: 421 - * @access public - * @param string $host - * @param int $port - * @param int $tval - * @return bool - */ - public function Connect($host, $port = 0, $tval = 30) { - // set the error val to null so there is no confusion - $this->error = null; - - // make sure we are __not__ connected - if($this->connected()) { - // already connected, generate error - $this->error = array("error" => G::LoadTranslation( 'ID_SMTP_ALREADY_CONNECTED' )); - return false; - } - - if(empty($port)) { - $port = $this->SMTP_PORT; - } - - // connect to the smtp server - $this->smtp_conn = @fsockopen($host, // the host of the server - $port, // the port to use - $errno, // error number if any - $errstr, // error message if any - $tval); // give up after ? secs - // verify we connected properly - if(empty($this->smtp_conn)) { - $this->error = array("error" => G::LoadTranslation( 'ID_SMTP_FAILED_CONNECT_SERVER' ), - "errno" => $errno, - "errstr" => $errstr); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '
'); - } - return false; - } - - // SMTP server can take longer to respond, give longer timeout for first read - // Windows does not have support for this timeout function - if(substr(PHP_OS, 0, 3) != "WIN") { - $max = ini_get('max_execution_time'); - if ($max != 0 && $tval > $max) { // don't bother if unlimited - @set_time_limit($tval); - } - stream_set_timeout($this->smtp_conn, $tval, 0); - } - - // get any announcement - $announce = $this->get_lines(); - - if($this->do_debug >= 2) { - $this->edebug("SMTP -> FROM SERVER:" . $announce . $this->CRLF . '
'); - } - - return true; - } - - /** - * Initiate a TLS communication with the server. - * - * SMTP CODE 220 Ready to start TLS - * SMTP CODE 501 Syntax error (no parameters allowed) - * SMTP CODE 454 TLS not available due to temporary reason - * @access public - * @return bool success - */ - public function StartTLS() { - $this->error = null; # to avoid confusion - - if(!$this->connected()) { - $this->error = array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_START_TLS' )); - return false; - } - - fputs($this->smtp_conn,"STARTTLS" . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'); - } - - if($code != 220) { - $this->error = - array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_START_TLS_NOT_ACCEPTED' ), - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'); - } - return false; - } - - // Begin encrypted connection - if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { - return false; - } - - return true; - } - - /** - * Performs SMTP authentication. Must be run after running the - * Hello() method. Returns true if successfully authenticated. - * @access public - * @param string $username - * @param string $password - * @param string $authtype - * @param string $realm - * @param string $workstation - * @return bool - */ - public function Authenticate($username, $password, $authtype='LOGIN', $realm='', $workstation='') { - if (empty($authtype)) { - $authtype = 'LOGIN'; - } - - switch ($authtype) { - case 'PLAIN': - // Start authentication - fputs($this->smtp_conn,"AUTH PLAIN" . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($code != 334) { - $this->error = - array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_AUTH_NOT_ACCEPTED' ), - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'); - } - return false; - } - // Send encoded username and password - fputs($this->smtp_conn, base64_encode("\0".$username."\0".$password) . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($code != 235) { - $this->error = - array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_AUTH_NOT_ACCEPTED' ), - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'); - } - return false; - } - break; - case 'LOGIN': - // Start authentication - @fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($code != 334) { - $this->error = - array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_AUTH_NOT_ACCEPTED' ), - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'); - } - return false; - } - - // Send encoded username - fputs($this->smtp_conn, base64_encode($username) . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($code != 334) { - $this->error = - array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_USERNAME_NOT_ACCEPTED' ), - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'); - } - return false; - } - - // Send encoded password - fputs($this->smtp_conn, base64_encode($password) . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($code != 235) { - $this->error = - array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_PASSWORD_NOT_ACCEPTED' ), - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'); - } - return false; - } - break; - case 'NTLM': - /* - * ntlm_sasl_client.php - ** Bundled with Permission - ** - ** How to telnet in windows: http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx - ** PROTOCOL Documentation http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication - */ - require_once('extras/ntlm_sasl_client.php'); - $temp = new stdClass(); - $ntlm_client = new ntlm_sasl_client_class; - if(! $ntlm_client->Initialize($temp)){//let's test if every function its available - $this->error = array("error" => $temp->error); - if($this->do_debug >= 1) { - $this->edebug(G::LoadTranslation( 'ID_SMTP_ERROR_ENABLE_PHPINI' ) . ": " . $this->error["error"] . $this->CRLF); - } - return false; - } - $msg1 = $ntlm_client->TypeMsg1($realm, $workstation);//msg1 - - fputs($this->smtp_conn,"AUTH NTLM " . base64_encode($msg1) . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - - if($code != 334) { - $this->error = - array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_AUTH_NOT_ACCEPTED' ), - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF); - } - return false; - } - - $challange = substr($rply,3);//though 0 based, there is a white space after the 3 digit number....//msg2 - $challange = base64_decode($challange); - $ntlm_res = $ntlm_client->NTLMResponse(substr($challange,24,8),$password); - $msg3 = $ntlm_client->TypeMsg3($ntlm_res,$username,$realm,$workstation);//msg3 - // Send encoded username - fputs($this->smtp_conn, base64_encode($msg3) . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($code != 235) { - $this->error = - array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_COULD_NOT_AUTH' ), - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF); - } - return false; - } - break; - } - return true; - } - - /** - * Returns true if connected to a server otherwise false - * @access public - * @return bool - */ - public function Connected() { - if(!empty($this->smtp_conn)) { - $sock_status = socket_get_status($this->smtp_conn); - if($sock_status["eof"]) { - // the socket is valid but we are not connected - if($this->do_debug >= 1) { - $this->edebug("SMTP -> NOTICE:" . $this->CRLF . G::LoadTranslation( 'ID_SMTP_ERROR_EOF_CAUGHT' )); - } - $this->Close(); - return false; - } - return true; // everything looks good - } - return false; - } - - /** - * Closes the socket and cleans up the state of the class. - * It is not considered good to use this function without - * first trying to use QUIT. - * @access public - * @return void - */ - public function Close() { - $this->error = null; // so there is no confusion - $this->helo_rply = null; - if(!empty($this->smtp_conn)) { - // close the connection and cleanup - fclose($this->smtp_conn); - $this->smtp_conn = 0; - } - } - - ///////////////////////////////////////////////// - // SMTP COMMANDS - ///////////////////////////////////////////////// - - /** - * Issues a data command and sends the msg_data to the server - * finializing the mail transaction. $msg_data is the message - * that is to be send with the headers. Each header needs to be - * on a single line followed by a with the message headers - * and the message body being seperated by and additional . - * - * Implements rfc 821: DATA - * - * SMTP CODE INTERMEDIATE: 354 - * [data] - * . - * SMTP CODE SUCCESS: 250 - * SMTP CODE FAILURE: 552,554,451,452 - * SMTP CODE FAILURE: 451,554 - * SMTP CODE ERROR : 500,501,503,421 - * @access public - * @param string $msg_data - * @return bool - */ - public function Data($msg_data) { - $this->error = null; // so no confusion is caused - - if(!$this->connected()) { - $this->error = array( - "error" => G::LoadTranslation( 'ID_SMTP_ERROR_CALLED_DATA_WITHOUT' )); - return false; - } - - fputs($this->smtp_conn,"DATA" . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'); - } - - if($code != 354) { - $this->error = - array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_DATA_COM_NOT_ACCEPTED' ), - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'); - } - return false; - } - - /* the server is ready to accept data! - * according to rfc 821 we should not send more than 1000 - * including the CRLF - * characters on a single line so we will break the data up - * into lines by \r and/or \n then if needed we will break - * each of those into smaller lines to fit within the limit. - * in addition we will be looking for lines that start with - * a period '.' and append and additional period '.' to that - * line. NOTE: this does not count towards limit. - */ - - // normalize the line breaks so we know the explode works - $msg_data = str_replace("\r\n","\n",$msg_data); - $msg_data = str_replace("\r","\n",$msg_data); - $lines = explode("\n",$msg_data); - - /* we need to find a good way to determine is headers are - * in the msg_data or if it is a straight msg body - * currently I am assuming rfc 822 definitions of msg headers - * and if the first field of the first line (':' sperated) - * does not contain a space then it _should_ be a header - * and we can process all lines before a blank "" line as - * headers. - */ - - $field = substr($lines[0],0,strpos($lines[0],":")); - $in_headers = false; - if(!empty($field) && !strstr($field," ")) { - $in_headers = true; - } - - $max_line_length = 998; // used below; set here for ease in change - - while(list(,$line) = @each($lines)) { - $lines_out = null; - if($line == "" && $in_headers) { - $in_headers = false; - } - // ok we need to break this line up into several smaller lines - while(strlen($line) > $max_line_length) { - $pos = strrpos(substr($line,0,$max_line_length)," "); - - // Patch to fix DOS attack - if(!$pos) { - $pos = $max_line_length - 1; - $lines_out[] = substr($line,0,$pos); - $line = substr($line,$pos); - } else { - $lines_out[] = substr($line,0,$pos); - $line = substr($line,$pos + 1); - } - - /* if processing headers add a LWSP-char to the front of new line - * rfc 822 on long msg headers - */ - if($in_headers) { - $line = "\t" . $line; - } - } - $lines_out[] = $line; - - // send the lines to the server - while(list(,$line_out) = @each($lines_out)) { - if(strlen($line_out) > 0) - { - if(substr($line_out, 0, 1) == ".") { - $line_out = "." . $line_out; - } - } - fputs($this->smtp_conn,$line_out . $this->CRLF); - } - } - - // message data has been sent - fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'); - } - - if($code != 250) { - $this->error = - array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_DATA_NOT_ACCEPTED' ), - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'); - } - return false; - } - return true; - } - - /** - * Sends the HELO command to the smtp server. - * This makes sure that we and the server are in - * the same known state. - * - * Implements from rfc 821: HELO - * - * SMTP CODE SUCCESS: 250 - * SMTP CODE ERROR : 500, 501, 504, 421 - * @access public - * @param string $host - * @return bool - */ - public function Hello($host = '') { - $this->error = null; // so no confusion is caused - - if(!$this->connected()) { - $this->error = array( - "error" => G::LoadTranslation( 'ID_SMTP_ERROR_CALLED_HELLO_WITHOUT' )); - return false; - } - - // if hostname for HELO was not specified send default - if(empty($host)) { - // determine appropriate default to send to server - $host = "localhost"; - } - - // Send extended hello first (RFC 2821) - if(!$this->SendHello("EHLO", $host)) { - if(!$this->SendHello("HELO", $host)) { - return false; - } - } - - return true; - } - - /** - * Sends a HELO/EHLO command. - * @access private - * @param string $hello - * @param string $host - * @return bool - */ - private function SendHello($hello, $host) { - fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - $this->edebug("SMTP -> FROM SERVER: " . $rply . $this->CRLF . '
'); - } - - if($code != 250) { - $this->error = - array("error" => $hello . ' ' . G::LoadTranslation( 'ID_SMTP_ERROR_NOT_ACCEPTED' ), - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'); - } - return false; - } - - $this->helo_rply = $rply; - - return true; - } - - /** - * Starts a mail transaction from the email address specified in - * $from. Returns true if successful or false otherwise. If True - * the mail transaction is started and then one or more Recipient - * commands may be called followed by a Data command. - * - * Implements rfc 821: MAIL FROM: - * - * SMTP CODE SUCCESS: 250 - * SMTP CODE SUCCESS: 552,451,452 - * SMTP CODE SUCCESS: 500,501,421 - * @access public - * @param string $from - * @return bool - */ - public function Mail($from) { - $this->error = null; // so no confusion is caused - - if(!$this->connected()) { - $this->error = array( - "error" => G::LoadTranslation( 'ID_SMTP_ERROR_CALLED_MAIL_WITHOUT' )); - return false; - } - - $useVerp = ($this->do_verp ? " XVERP" : ""); - fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'); - } - - if($code != 250) { - $this->error = - array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_MAIL_NOT_ACCEPTED' ), - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'); - } - return false; - } - return true; - } - - /** - * Sends the quit command to the server and then closes the socket - * if there is no error or the $close_on_error argument is true. - * - * Implements from rfc 821: QUIT - * - * SMTP CODE SUCCESS: 221 - * SMTP CODE ERROR : 500 - * @access public - * @param bool $close_on_error - * @return bool - */ - public function Quit($close_on_error = true) { - $this->error = null; // so there is no confusion - - if(!$this->connected()) { - $this->error = array( - "error" => G::LoadTranslation( 'ID_SMTP_ERROR_CALLED_QUIT_WITHOUT' )); - return false; - } - - // send the quit command to the server - fputs($this->smtp_conn,"quit" . $this->CRLF); - - // get any good-bye messages - $byemsg = $this->get_lines(); - - if($this->do_debug >= 2) { - $this->edebug("SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '
'); - } - - $rval = true; - $e = null; - - $code = substr($byemsg,0,3); - if($code != 221) { - // use e as a tmp var cause Close will overwrite $this->error - $e = array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_SERVER_REJECTED' ), - "smtp_code" => $code, - "smtp_rply" => substr($byemsg,4)); - $rval = false; - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '
'); - } - } - - if(empty($e) || $close_on_error) { - $this->Close(); - } - - return $rval; - } - - /** - * Sends the command RCPT to the SMTP server with the TO: argument of $to. - * Returns true if the recipient was accepted false if it was rejected. - * - * Implements from rfc 821: RCPT TO: - * - * SMTP CODE SUCCESS: 250,251 - * SMTP CODE FAILURE: 550,551,552,553,450,451,452 - * SMTP CODE ERROR : 500,501,503,421 - * @access public - * @param string $to - * @return bool - */ - public function Recipient($to) { - $this->error = null; // so no confusion is caused - - if(!$this->connected()) { - $this->error = array( - "error" => G::LoadTranslation( 'ID_SMTP_ERROR_CALLED_RECIPIENT_WITHOUT' )); - return false; - } - - fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'); - } - - if($code != 250 && $code != 251) { - $this->error = - array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_RCPT_NOT_ACCEPTED' ), - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'); - } - return false; - } - return true; - } - - /** - * Sends the RSET command to abort and transaction that is - * currently in progress. Returns true if successful false - * otherwise. - * - * Implements rfc 821: RSET - * - * SMTP CODE SUCCESS: 250 - * SMTP CODE ERROR : 500,501,504,421 - * @access public - * @return bool - */ - public function Reset() { - $this->error = null; // so no confusion is caused - - if(!$this->connected()) { - $this->error = array( - "error" => G::LoadTranslation( 'ID_SMTP_ERROR_CALLED_RESET_WITHOUT' )); - return false; - } - - fputs($this->smtp_conn,"RSET" . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'); - } - - if($code != 250) { - $this->error = - array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_RSET_FAILED' ), - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'); - } - return false; - } - - return true; - } - - /** - * Starts a mail transaction from the email address specified in - * $from. Returns true if successful or false otherwise. If True - * the mail transaction is started and then one or more Recipient - * commands may be called followed by a Data command. This command - * will send the message to the users terminal if they are logged - * in and send them an email. - * - * Implements rfc 821: SAML FROM: - * - * SMTP CODE SUCCESS: 250 - * SMTP CODE SUCCESS: 552,451,452 - * SMTP CODE SUCCESS: 500,501,502,421 - * @access public - * @param string $from - * @return bool - */ - public function SendAndMail($from) { - $this->error = null; // so no confusion is caused - - if(!$this->connected()) { - $this->error = array( - "error" => G::LoadTranslation( 'ID_SMTP_ERROR_CALLED_SENDANDMAIL_WITHOUT' )); - return false; - } - - fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'); - } - - if($code != 250) { - $this->error = - array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_SAML_NOT_ACCEPTED' ), - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'); - } - return false; - } - return true; - } - - /** - * This is an optional command for SMTP that this class does not - * support. This method is here to make the RFC821 Definition - * complete for this class and __may__ be implimented in the future - * - * Implements from rfc 821: TURN - * - * SMTP CODE SUCCESS: 250 - * SMTP CODE FAILURE: 502 - * SMTP CODE ERROR : 500, 503 - * @access public - * @return bool - */ - public function Turn() { - $this->error = array("error" => G::LoadTranslation( 'ID_SMTP_ERROR_MET_TURN_SMTP_NOT_IMPLEMENTED' )); - if($this->do_debug >= 1) { - $this->edebug("SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '
'); - } - return false; - } - - /** - * Get the current error - * @access public - * @return array - */ - public function getError() { - return $this->error; - } - - ///////////////////////////////////////////////// - // INTERNAL FUNCTIONS - ///////////////////////////////////////////////// - - /** - * Read in as many lines as possible - * either before eof or socket timeout occurs on the operation. - * With SMTP we can tell if we have more lines to read if the - * 4th character is '-' symbol. If it is a space then we don't - * need to read anything else. - * @access private - * @return string - */ - private function get_lines() { - $data = ""; - $endtime = 0; - /* If for some reason the fp is bad, don't inf loop */ - if (!is_resource($this->smtp_conn)) { - return $data; - } - stream_set_timeout($this->smtp_conn, $this->Timeout); - if ($this->Timelimit > 0) { - $endtime = time() + $this->Timelimit; - } - while(is_resource($this->smtp_conn) && !feof($this->smtp_conn)) { - $str = @fgets($this->smtp_conn,515); - if($this->do_debug >= 4) { - $this->edebug("SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '
'); - $this->edebug("SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '
'); - } - $data .= $str; - if($this->do_debug >= 4) { - $this->edebug("SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '
'); - } - // if 4th character is a space, we are done reading, break the loop - if(substr($str,3,1) == " ") { break; } - // Timed-out? Log and break - $info = stream_get_meta_data($this->smtp_conn); - if ($info['timed_out']) { - if($this->do_debug >= 4) { - $this->edebug("SMTP -> get_lines(): timed-out (" . $this->Timeout . " seconds)
"); - } - break; - } - // Now check if reads took too long - if ($endtime) { - if (time() > $endtime) { - if($this->do_debug >= 4) { - $this->edebug("SMTP -> get_lines(): timelimit reached (" . $this->Timelimit . " seconds)
"); - } - break; - } - } - } - return $data; - } - -} -?> diff --git a/thirdparty/phpmailer/extras/class.html2text.inc b/thirdparty/phpmailer/extras/class.html2text.inc deleted file mode 100644 index 56c486ca7..000000000 --- a/thirdparty/phpmailer/extras/class.html2text.inc +++ /dev/null @@ -1,489 +0,0 @@ - * - * All rights reserved. * - * * - * This script is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * The GNU General Public License can be found at * - * http://www.gnu.org/copyleft/gpl.html. * - * * - * This script is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * Author(s): Jon Abernathy * - * * - * Last modified: 08/08/07 * - * * - *************************************************************************/ - - -/** - * Takes HTML and converts it to formatted, plain text. - * - * Thanks to Alexander Krug (http://www.krugar.de/) to pointing out and - * correcting an error in the regexp search array. Fixed 7/30/03. - * - * Updated set_html() function's file reading mechanism, 9/25/03. - * - * Thanks to Joss Sanglier (http://www.dancingbear.co.uk/) for adding - * several more HTML entity codes to the $search and $replace arrays. - * Updated 11/7/03. - * - * Thanks to Darius Kasperavicius (http://www.dar.dar.lt/) for - * suggesting the addition of $allowed_tags and its supporting function - * (which I slightly modified). Updated 3/12/04. - * - * Thanks to Justin Dearing for pointing out that a replacement for the - *
tag was missing, and suggesting an appropriate fix. - * Updated 8/25/04. - * - * Thanks to Mathieu Collas (http://www.myefarm.com/) for finding a - * display/formatting bug in the _build_link_list() function: email - * readers would show the left bracket and number ("[1") as part of the - * rendered email address. - * Updated 12/16/04. - * - * Thanks to Wojciech Bajon (http://histeria.pl/) for submitting code - * to handle relative links, which I hadn't considered. I modified his - * code a bit to handle normal HTTP links and MAILTO links. Also for - * suggesting three additional HTML entity codes to search for. - * Updated 03/02/05. - * - * Thanks to Jacob Chandler for pointing out another link condition - * for the _build_link_list() function: "https". - * Updated 04/06/05. - * - * Thanks to Marc Bertrand (http://www.dresdensky.com/) for - * suggesting a revision to the word wrapping functionality; if you - * specify a $width of 0 or less, word wrapping will be ignored. - * Updated 11/02/06. - * - * *** Big housecleaning updates below: - * - * Thanks to Colin Brown (http://www.sparkdriver.co.uk/) for - * suggesting the fix to handle and blank lines (whitespace). - * Christian Basedau (http://www.movetheweb.de/) also suggested the - * blank lines fix. - * - * Special thanks to Marcus Bointon (http://www.synchromedia.co.uk/), - * Christian Basedau, Norbert Laposa (http://ln5.co.uk/), - * Bas van de Weijer, and Marijn van Butselaar - * for pointing out my glaring error in the handling. Marcus also - * supplied a host of fixes. - * - * Thanks to Jeffrey Silverman (http://www.newtnotes.com/) for pointing - * out that extra spaces should be compressed--a problem addressed with - * Marcus Bointon's fixes but that I had not yet incorporated. - * - * Thanks to Daniel Schledermann (http://www.typoconsult.dk/) for - * suggesting a valuable fix with tag handling. - * - * Thanks to Wojciech Bajon (again!) for suggesting fixes and additions, - * including the tag handling that Daniel Schledermann pointed - * out but that I had not yet incorporated. I haven't (yet) - * incorporated all of Wojciech's changes, though I may at some - * future time. - * - * *** End of the housecleaning updates. Updated 08/08/07. - * - * @author Jon Abernathy - * @version 1.0.0 - * @since PHP 4.0.2 - */ -class html2text -{ - - /** - * Contains the HTML content to convert. - * - * @var string $html - * @access public - */ - var $html; - - /** - * Contains the converted, formatted text. - * - * @var string $text - * @access public - */ - var $text; - - /** - * Maximum width of the formatted text, in columns. - * - * Set this value to 0 (or less) to ignore word wrapping - * and not constrain text to a fixed-width column. - * - * @var integer $width - * @access public - */ - var $width = 70; - - /** - * List of preg* regular expression patterns to search for, - * used in conjunction with $replace. - * - * @var array $search - * @access public - * @see $replace - */ - var $search = array( - "/\r/", // Non-legal carriage return - "/[\n\t]+/", // Newlines and tabs - '/[ ]{2,}/', // Runs of spaces, pre-handling - '/]*>.*?<\/script>/i', // - -
- $msg + " . $this->getSessionMessageForSupervisor() . " @@ -1320,6 +1292,7 @@ class PmDynaform $this->getTheStringVariableForGoogleMaps() . "\n" . "\n" . "\n" . + $this->getSessionMessage() . "
\n" . " \n" . " \n" . @@ -1356,9 +1329,20 @@ class PmDynaform exit(); } + /** + * Print PmDynaform for Action by Email. + * + * @param array $record + * @return string + * + * @see ActionsByEmailCoreClass->sendActionsByEmail() + * @link https://wiki.processmaker.com/3.3/Actions_by_Email + */ public function printPmDynaformAbe($record) { - ob_clean(); + if (ob_get_length() > 0) { + ob_clean(); + } $this->record = $record; $json = G::json_decode($this->record["DYN_CONTENT"]); $this->jsonr($json); @@ -1576,19 +1560,27 @@ class PmDynaform } } + /** + * Verify the use of the variable in all the forms of the process. + * + * @param string $processUid + * @param string $variable + * @return boolean | string + * + * @see ProcessMaker\BusinessModel\Variable->delete() + * @link https://wiki.processmaker.com/3.2/Variables#Managing_Variables + */ public function isUsed($processUid, $variable) { - $criteria = new Criteria("workflow"); - $criteria->addSelectColumn(DynaformPeer::DYN_UID); - $criteria->addSelectColumn(DynaformPeer::DYN_CONTENT); - $criteria->add(DynaformPeer::PRO_UID, $processUid, Criteria::EQUAL); - $rsCriteria = DynaformPeer::doSelectRS($criteria); - $rsCriteria->setFetchmode(ResultSet::FETCHMODE_ASSOC); - while ($rsCriteria->next()) { - $aRow = $rsCriteria->getRow(); - $json = G::json_decode($aRow['DYN_CONTENT']); + $result = ModelDynaform::getByProUid($processUid); + if (empty($result)) { + return false; + } + foreach ($result as $row) { + $dynaform = new PmDynaform(["CURRENT_DYNAFORM" => $row->DYN_UID]); + $json = G::json_decode($dynaform->record["DYN_CONTENT"]); if ($this->jsoni($json, $variable)) { - return $aRow['DYN_UID']; + return $row->DYN_UID; } } return false; @@ -2224,4 +2216,53 @@ class PmDynaform $result = 'var googleMaps = ' . G::json_encode($googleMaps) . ';'; return $result; } + + /** + * Get session message. + * + * @return string + * + * @see PmDynaform->printEdit() + * @see PmDynaform->printABE() + * @link https://wiki.processmaker.com/3.1/Multiple_File_Uploader#File_Extensions + */ + public function getSessionMessage() + { + $message = ""; + if (isset($_SESSION['G_MESSAGE_TYPE']) && isset($_SESSION['G_MESSAGE'])) { + $color = "green"; + if ($_SESSION['G_MESSAGE_TYPE'] === "ERROR") { + $color = "red"; + } + if ($_SESSION['G_MESSAGE_TYPE'] === "WARNING") { + $color = "#C3C380"; + } + if ($_SESSION['G_MESSAGE_TYPE'] === "INFO") { + $color = "green"; + } + $message = "
" . $_SESSION['G_MESSAGE_TYPE'] . ": " . $_SESSION['G_MESSAGE'] . "
"; + unset($_SESSION['G_MESSAGE_TYPE']); + unset($_SESSION['G_MESSAGE']); + } + return $message; + } + + /** + * Get session message for supervisor. + * + * @return string + * + * @see PmDynaform->printEditSupervisor(); + * @link https://wiki.processmaker.com/3.1/Multiple_File_Uploader#File_Extensions + */ + public function getSessionMessageForSupervisor() + { + $message = ""; + if (isset($_SESSION["G_MESSAGE_TYPE"]) && isset($_SESSION["G_MESSAGE"])) { + $message = "
" . G::LoadTranslation("ID_INFO") . ": " . $_SESSION["G_MESSAGE"] . "
"; + unset($_SESSION["G_MESSAGE_TYPE"]); + unset($_SESSION["G_MESSAGE"]); + } + return $message; + } } diff --git a/workflow/engine/classes/PmTable.php b/workflow/engine/classes/PmTable.php index b6e7eb075..11a1e7490 100644 --- a/workflow/engine/classes/PmTable.php +++ b/workflow/engine/classes/PmTable.php @@ -1006,4 +1006,24 @@ class PmTable } return $oCriteria; } + + /** + * Get the type of the column ex: string, int, double, boolean + * + * @param string $pmTablePeer + * @param string $tableName + * @param string $columnName + * + * @return string + */ + public static function getTypeOfColumn($pmTablePeer, $tableName, $columnName) + { + try { + $type = $pmTablePeer::getMapBuilder()->getDatabaseMap()->getTable($tableName)->getColumn($columnName)->getCreoleType(); + } catch (Exception $e) { + return ''; + } + + return $type; + } } diff --git a/workflow/engine/classes/ProcessMap.php b/workflow/engine/classes/ProcessMap.php index d6df7fc35..eb7c54390 100644 --- a/workflow/engine/classes/ProcessMap.php +++ b/workflow/engine/classes/ProcessMap.php @@ -4211,21 +4211,37 @@ class ProcessMap } } - public function downloadFile($sProcessUID, $sMainDirectory, $sCurrentDirectory, $sFile) + /** + * Stream a file from "mailTemplates" or "public" directory thats belongs to a process + * + * @param string $processUid + * @param string $mainDirectory + * @param string $currentDirectory + * @param string $file + */ + public function downloadFile($processUid, $mainDirectory, $currentDirectory, $file) { - switch ($sMainDirectory) { + // Validate directory and file requested + $filter = new InputFilter(); + $currentDirectory = $filter->validatePath($currentDirectory); + $file = $filter->validatePath($file); + + // Validate the main directory + switch ($mainDirectory) { case 'mailTemplates': - $sDirectory = PATH_DATA_MAILTEMPLATES . $sProcessUID . PATH_SEP . ($sCurrentDirectory != '' ? $sCurrentDirectory . PATH_SEP : ''); + $sDirectory = PATH_DATA_MAILTEMPLATES . $processUid . PATH_SEP . ($currentDirectory != '' ? $currentDirectory . PATH_SEP : ''); break; case 'public': - $sDirectory = PATH_DATA_PUBLIC . $sProcessUID . PATH_SEP . ($sCurrentDirectory != '' ? $sCurrentDirectory . PATH_SEP : ''); + $sDirectory = PATH_DATA_PUBLIC . $processUid . PATH_SEP . ($currentDirectory != '' ? $currentDirectory . PATH_SEP : ''); break; default: die(); break; } - if (file_exists($sDirectory . $sFile)) { - G::streamFile($sDirectory . $sFile, true); + + // Stream the file if path exists + if (file_exists($sDirectory . $file)) { + G::streamFile($sDirectory . $file, true); } } diff --git a/workflow/engine/classes/Processes.php b/workflow/engine/classes/Processes.php index c81813e60..43cdc8ce9 100644 --- a/workflow/engine/classes/Processes.php +++ b/workflow/engine/classes/Processes.php @@ -1029,7 +1029,7 @@ class Processes $oData->process['PRO_DYNAFORMS']['PROCESS'] = ''; } - if ($oData->process['PRO_DYNAFORMS']['PROCESS'] != '') { + if (!empty($oData->process['PRO_DYNAFORMS']['PROCESS']) && !empty($map[$oData->process['PRO_DYNAFORMS']['PROCESS']])) { $oData->process['PRO_DYNAFORMS']['PROCESS'] = $map[$oData->process['PRO_DYNAFORMS']['PROCESS']]; } @@ -1994,6 +1994,13 @@ class Processes $criteria->add(InputDocumentPeer::INP_DOC_MAX_FILESIZE, $row['INP_DOC_MAX_FILESIZE']); $criteria->add(InputDocumentPeer::INP_DOC_MAX_FILESIZE_UNIT, $row['INP_DOC_MAX_FILESIZE_UNIT']); BasePeer::doInsert($criteria, $con); + + //Insert in CONTENT + $labels = [ + 'INP_DOC_TITLE' => $row['INP_DOC_TITLE'], + 'INP_DOC_DESCRIPTION' => !empty($row['INP_DOC_DESCRIPTION']) ? $row['INP_DOC_DESCRIPTION'] : '' + ]; + $this->insertToContentTable($con, $labels, $row['INP_DOC_UID'], SYS_LANG); } $con->commit(); } catch (Exception $e) { @@ -2178,6 +2185,13 @@ class Processes $criteria->add(OutputDocumentPeer::OUT_DOC_PDF_SECURITY_PERMISSIONS, $row['OUT_DOC_PDF_SECURITY_PERMISSIONS']); $criteria->add(OutputDocumentPeer::OUT_DOC_OPEN_TYPE, $row['OUT_DOC_OPEN_TYPE']); BasePeer::doInsert($criteria, $con); + + //Insert in CONTENT + $labels = ['OUT_DOC_TITLE' => $row['OUT_DOC_TITLE'], + 'OUT_DOC_DESCRIPTION' => !empty($row['OUT_DOC_DESCRIPTION']) ? $row['OUT_DOC_DESCRIPTION'] : '', + 'OUT_DOC_FILENAME' => $row['OUT_DOC_FILENAME'], + 'OUT_DOC_TEMPLATE' => !empty($row['OUT_DOC_TEMPLATE']) ? $row['OUT_DOC_TEMPLATE'] : '']; + $this->insertToContentTable($con, $labels, $row['OUT_DOC_UID'], SYS_LANG); } $con->commit(); } catch (Exception $e) { @@ -3104,6 +3118,13 @@ class Processes $criteria->add(DynaformPeer::DYN_VERSION, $row['DYN_VERSION']); $criteria->add(DynaformPeer::DYN_UPDATE_DATE, $row['DYN_UPDATE_DATE']); BasePeer::doInsert($criteria, $con); + + //Insert in CONTENT + $labels = [ + 'DYN_TITLE' => $row['DYN_TITLE'], + 'DYN_DESCRIPTION' => !empty($row['DYN_DESCRIPTION']) ? $row['DYN_DESCRIPTION'] : '' + ]; + $this->insertToContentTable($con, $labels, $row['DYN_UID'], SYS_LANG); } $con->commit(); } catch (Exception $e) { @@ -3249,6 +3270,13 @@ class Processes $criteria->add(TriggersPeer::TRI_WEBBOT, $row['TRI_WEBBOT']); $criteria->add(TriggersPeer::TRI_PARAM, $row['TRI_PARAM']); BasePeer::doInsert($criteria, $con); + + //Insert in CONTENT + $labels = [ + 'TRI_TITLE' => $row['TRI_TITLE'], + 'TRI_DESCRIPTION' => !empty($row['TRI_DESCRIPTION']) ? $row['TRI_DESCRIPTION'] : '' + ]; + $this->insertToContentTable($con, $labels, $row['TRI_UID'], SYS_LANG); } $con->commit(); } catch (Exception $e) { @@ -4050,6 +4078,10 @@ class Processes $criteria->add(GroupwfPeer::GRP_LDAP_DN, $row['GRP_LDAP_DN']); $criteria->add(GroupwfPeer::GRP_UX, $row['GRP_UX']); BasePeer::doInsert($criteria, $con); + + //Insert in CONTENT + $labels = ['GRP_TITLE' => $row['GRP_TITLE']]; + $this->insertToContentTable($con, $labels, $row['GRP_UID'], SYS_LANG); } $con->commit(); } catch (Exception $e) { @@ -6375,4 +6407,38 @@ class Processes $proTitle = substr($proTitle, 0, strlen($proTitle) - $excess); return $proTitle; } + + /** + * Delete, insert and update labels in CONTENT related to a process element + * + * @param object $connection + * @param array $conCategories + * @param string $conId + * @param string $conLang + * @param string $conParent + */ + private function insertToContentTable($connection, array $conCategories, $conId, $conLang, $conParent = '') { + //Prepare to delete labels related in CONTENT + $criteria = new Criteria(ContentPeer::DATABASE_NAME); + $criteria->addSelectColumn('*'); + $criteria->add(ContentPeer::CON_CATEGORY, array_keys($conCategories), Criteria::IN); + $criteria->add(ContentPeer::CON_ID, $conId); + $criteria->add(ContentPeer::CON_LANG, $conLang); + $criteria->add(ContentPeer::CON_PARENT, $conParent); + BasePeer::doDelete($criteria, $connection); + + foreach ($conCategories as $conCategory => $conValue) { + //Prepare the insert label in CONTENT + $criteria = new Criteria(ContentPeer::DATABASE_NAME); + $criteria->add(ContentPeer::CON_CATEGORY, $conCategory); + $criteria->add(ContentPeer::CON_ID, $conId); + $criteria->add(ContentPeer::CON_LANG, $conLang); + $criteria->add(ContentPeer::CON_VALUE, $conValue); + $criteria->add(ContentPeer::CON_PARENT, $conParent); + BasePeer::doInsert($criteria, $connection); + + //Updating all related labels in CONTENT + Content::updateEqualValue($conCategory, $conParent, $conId, $conValue); + } + } } diff --git a/workflow/engine/classes/SpoolRun.php b/workflow/engine/classes/SpoolRun.php index 255aeda04..7ef0547a5 100644 --- a/workflow/engine/classes/SpoolRun.php +++ b/workflow/engine/classes/SpoolRun.php @@ -15,18 +15,19 @@ use ProcessMaker\Core\System; */ class SpoolRun { - public $config; + private $appUid; + private $appMsgUid; + private $warnings = []; //Array to store the warning that were throws by the class + private $exceptionCode = []; //Array to define the Exception codes private $fileData; - private $spool_id; - public $status; - public $error; - - private $ExceptionCode = Array(); //Array to define the Expetion codes - private $aWarnings = Array(); //Array to store the warning that were throws by the class - - private $longMailEreg; private $mailEreg; + private $spoolId; + + public $config; + public $error; + public $status; + /** * Class constructor - iniatilize default values @@ -38,18 +39,58 @@ class SpoolRun { $this->config = array(); $this->fileData = array(); - $this->spool_id = ''; + $this->spoolId = ''; $this->status = 'pending'; $this->error = ''; - $this->ExceptionCode['FATAL'] = 1; - $this->ExceptionCode['WARNING'] = 2; - $this->ExceptionCode['NOTICE'] = 3; + $this->exceptionCode['FATAL'] = 1; + $this->exceptionCode['WARNING'] = 2; + $this->exceptionCode['NOTICE'] = 3; $this->longMailEreg = "/(.*)(<([\w\-\+\.']+@[\w\-_\.]+\.\w{2,5})+>)/"; $this->mailEreg = "/^([\w\-_\+\.']+@[\w\-_\.]+\.\w{2,5}+)$/"; } + /** + * Get the appUid + * + * @return string + */ + public function getAppUid() + { + return $this->appUid; + } + + /** + * Set the appUid + * + * @param string $v + */ + public function setAppUid($v) + { + $this->appUid = $v; + } + + /** + * Get the appMsgUid + * + * @return string + */ + public function getAppMsgUid() + { + return $this->appMsgUid; + } + + /** + * Set the appMsgUid + * + * @param string $v + */ + public function setAppMsgUid($v) + { + $this->appMsgUid = $v; + } + /** * get all files into spool in a list * @@ -65,7 +106,7 @@ class SpoolRun $rs = $stmt->executeQuery(); while ($rs->next()) { - $this->spool_id = $rs->getString('APP_MSG_UID'); + $this->spoolId = $rs->getString('APP_MSG_UID'); $this->fileData['subject'] = $rs->getString('APP_MSG_SUBJECT'); $this->fileData['from'] = $rs->getString('APP_MSG_FROM'); $this->fileData['to'] = $rs->getString('APP_MSG_TO'); @@ -110,7 +151,7 @@ class SpoolRun $aData['app_msg_attach'] = serialize($attachment); $aData['app_msg_show_message'] = (isset($aData['app_msg_show_message'])) ? $aData['app_msg_show_message'] : 1; $aData["app_msg_error"] = (isset($aData["app_msg_error"])) ? $aData["app_msg_error"] : ''; - $sUID = $this->db_insert($aData); + $sUID = $this->dbInsert($aData); $aData['app_msg_date'] = isset($aData['app_msg_date']) ? $aData['app_msg_date'] : ''; @@ -178,7 +219,7 @@ class SpoolRun */ public function setData($sAppMsgUid, $sSubject, $sFrom, $sTo, $sBody, $sDate = "", $sCC = "", $sBCC = "", $sTemplate = "", $aAttachment = array(), $bContentTypeIsHtml = true, $sError = "") { - $this->spool_id = $sAppMsgUid; + $this->spoolId = $sAppMsgUid; $this->fileData['subject'] = $sSubject; $this->fileData['from'] = $sFrom; $this->fileData['to'] = $sTo; @@ -234,17 +275,40 @@ class SpoolRun */ private function updateSpoolStatus() { - $oAppMessage = AppMessagePeer::retrieveByPK($this->spool_id); + $oAppMessage = AppMessagePeer::retrieveByPK($this->spoolId); if (is_array($this->fileData['attachments'])) { $attachment = implode(",", $this->fileData['attachments']); $oAppMessage->setappMsgAttach($attachment); } $oAppMessage->setAppMsgStatus($this->status); $oAppMessage->setAppMsgStatusId(isset(AppMessage::$app_msg_status_values[$this->status]) ? AppMessage::$app_msg_status_values[$this->status] : 0); - $oAppMessage->setappMsgsenddate(date('Y-m-d H:i:s')); + $oAppMessage->setAppMsgSendDate(date('Y-m-d H:i:s')); $oAppMessage->save(); } + /** + * Update the error + * + * @param string $msgError + * + * @return void + * + * @see SpoolRun::handleMail() + */ + private function updateSpoolError($msgError) + { + $appMessage = AppMessagePeer::retrieveByPK($this->spoolId); + $appMessage->setAppMsgError($msgError); + $appMessage->setAppMsgSendDate(date('Y-m-d H:i:s')); + $appMessage->save(); + + $context = Bootstrap::getDefaultContextLog(); + $context["action"] = "Send email"; + $context["appMsgUid"] = $this->getAppMsgUid(); + $context["appUid"] = $this->getAppUid(); + Bootstrap::registerMonolog("SendEmail", 400, $msgError, $context); + } + /** * handle the email that was set in "TO" parameter * @@ -269,7 +333,7 @@ class SpoolRun } if (!isset($matches[3])) { - throw new Exception('Invalid email address in FROM parameter (' . $this->fileData['from'] . ')', $this->ExceptionCode['WARNING']); + throw new Exception('Invalid email address in FROM parameter (' . $this->fileData['from'] . ')', $this->exceptionCode['WARNING']); } $this->fileData['from_email'] = trim($matches[3]); @@ -279,7 +343,7 @@ class SpoolRun preg_match($ereg, $this->fileData["from"], $matches); if (!isset($matches[0])) { - throw new Exception('Invalid email address in FROM parameter (' . $this->fileData['from'] . ')', $this->ExceptionCode['WARNING']); + throw new Exception('Invalid email address in FROM parameter (' . $this->fileData['from'] . ')', $this->exceptionCode['WARNING']); } $this->fileData['from_name'] = ''; @@ -305,16 +369,17 @@ class SpoolRun } /** - * handle all recipients to compose the mail + * Handle all recipients to compose the mail * - * @param none - * @return boolean true or exception + * @return void + * + * @see SpoolRun::sendMail() */ private function handleEnvelopeTo() { - $hold = array(); - $holdcc = array(); - $holdbcc = array(); + $hold = []; + $holdcc = []; + $holdbcc = []; $text = trim($this->fileData['to']); $textcc = ''; @@ -335,10 +400,15 @@ class SpoolRun $this->fileData['envelope_to'][] = "$val"; } } + } elseif ($text != '') { $this->fileData['envelope_to'][] = "$text"; } else { - $this->fileData['envelope_to'] = Array(); + $this->fileData['envelope_to'] = []; + } + + if (empty($this->fileData['envelope_to'])){ + $this->updateSpoolError('Invalid address: ' . $text); } //CC @@ -353,7 +423,7 @@ class SpoolRun } elseif ($textcc != '') { $this->fileData['envelope_cc'][] = "$textcc"; } else { - $this->fileData['envelope_cc'] = Array(); + $this->fileData['envelope_cc'] = []; } //BCC @@ -368,16 +438,19 @@ class SpoolRun } elseif ($textbcc != '') { $this->fileData['envelope_bcc'][] = "$textbcc"; } else { - $this->fileData['envelope_bcc'] = Array(); + $this->fileData['envelope_bcc'] = []; } } /** - * handle and compose the email content and parameters + * Handle and compose the email content and parameters * - * @param none - * @return none + * @return void + * + * @throws Exception + * + * @see SpoolRun::sendMail() */ private function handleMail() { @@ -386,20 +459,18 @@ class SpoolRun switch ($this->config['MESS_ENGINE']) { case 'MAIL': case 'PHPMAILER': - - switch ($this->config['MESS_ENGINE']) { case 'MAIL': - $oPHPMailer = new PHPMailer(); - $oPHPMailer->Mailer = 'mail'; + $phpMailer = new PHPMailer(); + $phpMailer->Mailer = 'mail'; break; case 'PHPMAILER': - $oPHPMailer = new PHPMailer(true); - $oPHPMailer->Mailer = 'smtp'; + $phpMailer = new PHPMailer(true); + $phpMailer->Mailer = 'smtp'; break; } - $oPHPMailer->SMTPAuth = (isset($this->config['SMTPAuth']) ? $this->config['SMTPAuth'] : ''); + $phpMailer->SMTPAuth = (isset($this->config['SMTPAuth']) ? $this->config['SMTPAuth'] : ''); switch ($this->config['MESS_ENGINE']) { case 'MAIL': @@ -407,101 +478,133 @@ class SpoolRun case 'PHPMAILER': //Posible Options for SMTPSecure are: "", "ssl" or "tls" if (isset($this->config['SMTPSecure']) && preg_match('/^(ssl|tls)$/', $this->config['SMTPSecure'])) { - $oPHPMailer->SMTPSecure = $this->config['SMTPSecure']; + $phpMailer->SMTPSecure = $this->config['SMTPSecure']; } break; } - $systemConfiguration = System::getSystemConfiguration(); - $oPHPMailer->Timeout = is_numeric($systemConfiguration['smtp_timeout']) ? $systemConfiguration['smtp_timeout'] : 20; - $oPHPMailer->CharSet = "UTF-8"; - $oPHPMailer->Encoding = "8bit"; - $oPHPMailer->Host = $this->config['MESS_SERVER']; - $oPHPMailer->Port = $this->config['MESS_PORT']; - $oPHPMailer->Username = $this->config['MESS_ACCOUNT']; - $oPHPMailer->Password = $this->config['MESS_PASSWORD']; - $oPHPMailer->SetFrom($this->fileData['from_email'], utf8_decode($this->fileData['from_name'])); - if (isset($this->fileData['reply_to'])) { - if ($this->fileData['reply_to'] != '') { - $oPHPMailer->AddReplyTo($this->fileData['reply_to'], $this->fileData['reply_to_name']); - } - } + try { + $systemConfiguration = System::getSystemConfiguration(); + $phpMailer->Timeout = is_numeric($systemConfiguration['smtp_timeout']) ? $systemConfiguration['smtp_timeout'] : 20; + $phpMailer->CharSet = "UTF-8"; + $phpMailer->Encoding = "8bit"; + $phpMailer->Host = $this->config['MESS_SERVER']; + $phpMailer->Port = $this->config['MESS_PORT']; + $phpMailer->Username = $this->config['MESS_ACCOUNT']; + $phpMailer->Password = $this->config['MESS_PASSWORD']; - $msSubject = $this->fileData['subject']; - - if (!(mb_detect_encoding($msSubject, "UTF-8") == "UTF-8")) { - $msSubject = utf8_encode($msSubject); - } - - $oPHPMailer->Subject = $msSubject; - - $msBody = $this->fileData['body']; - - if (!(mb_detect_encoding($msBody, "UTF-8") == "UTF-8")) { - $msBody = utf8_encode($msBody); - } - - $oPHPMailer->Body = $msBody; - - $attachment = @unserialize($this->fileData['attachments']); - if ($attachment === false) { - $attachment = $this->fileData['attachments']; - } - if (is_array($attachment)) { - foreach ($attachment as $key => $fileAttach) { - if (file_exists($fileAttach)) { - $oPHPMailer->AddAttachment($fileAttach, is_int($key) ? '' : $key); + //From + $phpMailer->SetFrom($this->fileData['from_email'], utf8_decode($this->fileData['from_name'])); + //Reply to + if (isset($this->fileData['reply_to'])) { + if ($this->fileData['reply_to'] != '') { + $phpMailer->AddReplyTo($this->fileData['reply_to'], $this->fileData['reply_to_name']); } } - } - - foreach ($this->fileData['envelope_to'] as $sEmail) { - if (strpos($sEmail, '<') !== false) { - preg_match($this->longMailEreg, $sEmail, $matches); - $sTo = trim($matches[3]); - $sToName = trim($matches[1]); - $oPHPMailer->AddAddress($sTo, $sToName); - } else { - $oPHPMailer->AddAddress($sEmail); + //Subject + $msSubject = $this->fileData['subject']; + if (!(mb_detect_encoding($msSubject, "UTF-8") == "UTF-8")) { + $msSubject = utf8_encode($msSubject); } - } - - //CC - foreach ($this->fileData['envelope_cc'] as $sEmail) { - if (strpos($sEmail, '<') !== false) { - preg_match($this->longMailEreg, $sEmail, $matches); - $sTo = trim($matches[3]); - $sToName = trim($matches[1]); - $oPHPMailer->AddCC($sTo, $sToName); - } else { - $oPHPMailer->AddCC($sEmail); + $phpMailer->Subject = $msSubject; + //Body + $msBody = $this->fileData['body']; + if (!(mb_detect_encoding($msBody, "UTF-8") == "UTF-8")) { + $msBody = utf8_encode($msBody); } - } - - //BCC - foreach ($this->fileData['envelope_bcc'] as $sEmail) { - if (strpos($sEmail, '<') !== false) { - preg_match($this->longMailEreg, $sEmail, $matches); - $sTo = trim($matches[3]); - $sToName = trim($matches[1]); - $oPHPMailer->AddBCC($sTo, $sToName); - } else { - $oPHPMailer->AddBCC($sEmail); + $phpMailer->Body = $msBody; + //Attachments + $attachment = @unserialize($this->fileData['attachments']); + if ($attachment === false) { + $attachment = $this->fileData['attachments']; } - } + if (is_array($attachment)) { + foreach ($attachment as $key => $fileAttach) { + if (file_exists($fileAttach)) { + $phpMailer->AddAttachment($fileAttach, is_int($key) ? '' : $key); + } + } + } + //To + foreach ($this->fileData['envelope_to'] as $email) { + if (strpos($email, '<') !== false) { + preg_match($this->longMailEreg, $email, $matches); + $toAddress = ''; + if (!empty($matches[3])) { + $toAddress = trim($matches[3]); + } + $toName = ''; + if (!empty($matches[1])) { + $toName = trim($matches[1]); + } + if (!empty($toAddress)) { + $phpMailer->AddAddress($toAddress, $toName); + } else { + throw new Exception('Invalid address: ' . $email); + } + } else { + $phpMailer->AddAddress($email); + } + } + //CC + foreach ($this->fileData['envelope_cc'] as $email) { + if (strpos($email, '<') !== false) { + preg_match($this->longMailEreg, $email, $matches); + $ccAddress = ''; + if (!empty($matches[3])) { + $ccAddress = trim($matches[3]); + } + $ccName = ''; + if (!empty($matches[1])) { + $ccName = trim($matches[1]); + } + if (!empty($ccAddress)) { + $phpMailer->AddCC($ccAddress, $ccName); + } else { + throw new Exception('Invalid address: ' . $email); + } + } else { + $phpMailer->AddCC($email); + } + } + //BCC + foreach ($this->fileData['envelope_bcc'] as $email) { + if (strpos($email, '<') !== false) { + preg_match($this->longMailEreg, $email, $matches); + $bccAddress = ''; + if (!empty($matches[3])) { + $bccAddress = trim($matches[3]); + } + $bccName = ''; + if (!empty($matches[1])) { + $bccName = trim($matches[1]); + } + if (!empty($bccAddress)) { + $phpMailer->AddBCC($bccAddress, $bccName); + } else { + throw new Exception('Invalid address: ' . $email); + } + } else { + $phpMailer->AddBCC($email); + } + } + //IsHtml + $phpMailer->IsHTML($this->fileData["contentTypeIsHtml"]); - $oPHPMailer->IsHTML($this->fileData["contentTypeIsHtml"]); + if ($this->config['MESS_ENGINE'] == 'MAIL') { + $phpMailer->WordWrap = 300; + } - if ($this->config['MESS_ENGINE'] == 'MAIL') { - $oPHPMailer->WordWrap = 300; - } - - if ($oPHPMailer->Send()) { - $this->error = ''; - $this->status = 'sent'; - } else { - $this->error = $oPHPMailer->ErrorInfo; - $this->status = 'failed'; + if ($phpMailer->Send()) { + $this->error = ''; + $this->status = 'sent'; + } else { + $this->error = $phpMailer->ErrorInfo; + $this->status = 'failed'; + $this->updateSpoolError($this->error); + } + } catch (Exception $error) { + $this->updateSpoolError($error->getMessage()); } break; case 'OPENMAIL': @@ -605,8 +708,8 @@ class SpoolRun } catch (Exception $e) { $strAux = "Spool::resendEmails(): Using " . $configuration["MESS_ENGINE"] . " for APP_MGS_UID=" . $row["APP_MSG_UID"] . " -> With message: " . $e->getMessage(); - if ($e->getCode() == $this->ExceptionCode["WARNING"]) { - array_push($this->aWarnings, $strAux); + if ($e->getCode() == $this->exceptionCode["WARNING"]) { + array_push($this->warnings, $strAux); continue; } else { error_log('<400> ' . $strAux); @@ -625,47 +728,54 @@ class SpoolRun */ public function getWarnings() { - if (sizeof($this->aWarnings) != 0) { - return $this->aWarnings; + if (sizeof($this->warnings) != 0) { + return $this->warnings; } return false; } /** - * db_insert + * Insert the record in the AppMessage * - * @param array $db_spool - * @return string $sUID; + * @param array $dbSpool + * + * @return string + * + * @see SpoolRun::create() */ - public function db_insert($db_spool) + public function dbInsert($dbSpool) { - $sUID = G::generateUniqueID(); + $appMsgUid = G::generateUniqueID(); + //Set some values for generate the log + $this->setAppMsgUid($appMsgUid); + $this->setAppUid($dbSpool['app_uid']); + //Set values for register the record $spool = new AppMessage(); - $spool->setAppMsgUid($sUID); - $spool->setMsgUid($db_spool['msg_uid']); - $spool->setAppUid($db_spool['app_uid']); - $spool->setDelIndex($db_spool['del_index']); - $spool->setAppMsgType($db_spool['app_msg_type']); - $spool->setAppMsgTypeId(isset(AppMessage::$app_msg_type_values[$db_spool['app_msg_type']]) ? AppMessage::$app_msg_type_values[$db_spool['app_msg_type']] : 0); - $spool->setAppMsgSubject($db_spool['app_msg_subject']); - $spool->setAppMsgFrom($db_spool['app_msg_from']); - $spool->setAppMsgTo($db_spool['app_msg_to']); - $spool->setAppMsgBody($db_spool['app_msg_body']); + $spool->setAppMsgUid($appMsgUid); + $spool->setMsgUid($dbSpool['msg_uid']); + $spool->setAppUid($dbSpool['app_uid']); + $spool->setDelIndex($dbSpool['del_index']); + $spool->setAppMsgType($dbSpool['app_msg_type']); + $spool->setAppMsgTypeId(isset(AppMessage::$app_msg_type_values[$dbSpool['app_msg_type']]) ? AppMessage::$app_msg_type_values[$dbSpool['app_msg_type']] : 0); + $spool->setAppMsgSubject($dbSpool['app_msg_subject']); + $spool->setAppMsgFrom($dbSpool['app_msg_from']); + $spool->setAppMsgTo($dbSpool['app_msg_to']); + $spool->setAppMsgBody($dbSpool['app_msg_body']); $spool->setAppMsgDate(date('Y-m-d H:i:s')); - $spool->setAppMsgCc($db_spool['app_msg_cc']); - $spool->setAppMsgBcc($db_spool['app_msg_bcc']); - $spool->setappMsgAttach($db_spool['app_msg_attach']); - $spool->setAppMsgTemplate($db_spool['app_msg_template']); - $spool->setAppMsgStatus($db_spool['app_msg_status']); - $spool->setAppMsgStatusId(isset(AppMessage::$app_msg_status_values[$db_spool['app_msg_status']]) ? AppMessage::$app_msg_status_values[$db_spool['app_msg_status']] : 0); + $spool->setAppMsgCc($dbSpool['app_msg_cc']); + $spool->setAppMsgBcc($dbSpool['app_msg_bcc']); + $spool->setappMsgAttach($dbSpool['app_msg_attach']); + $spool->setAppMsgTemplate($dbSpool['app_msg_template']); + $spool->setAppMsgStatus($dbSpool['app_msg_status']); + $spool->setAppMsgStatusId(isset(AppMessage::$app_msg_status_values[$dbSpool['app_msg_status']]) ? AppMessage::$app_msg_status_values[$dbSpool['app_msg_status']] : 0); $spool->setAppMsgSendDate(date('Y-m-d H:i:s')); - $spool->setAppMsgShowMessage($db_spool['app_msg_show_message']); - $spool->setAppMsgError($db_spool['app_msg_error']); + $spool->setAppMsgShowMessage($dbSpool['app_msg_show_message']); + $spool->setAppMsgError($dbSpool['app_msg_error']); $appDelegation = new AppDelegation(); - if (empty($db_spool['app_number'])) { - $delegationIds = $appDelegation->getColumnIds($db_spool['app_uid'], $db_spool['del_index']); + if (empty($dbSpool['app_number'])) { + $delegationIds = $appDelegation->getColumnIds($dbSpool['app_uid'], $dbSpool['del_index']); if (is_array($delegationIds) && count($delegationIds) > 0) { $delegationIds = array_change_key_case($delegationIds); $appNumber = $delegationIds['app_number']; @@ -674,19 +784,19 @@ class SpoolRun $appNumber = 0; } } else { - $appNumber = $db_spool['app_number']; + $appNumber = $dbSpool['app_number']; } - if (empty($db_spool['tas_id'])) { + if (empty($dbSpool['tas_id'])) { $tasId = isset($delegationIds['tas_id']) ? $delegationIds['tas_id'] : 0; } else { - $tasId = $db_spool['tas_id']; + $tasId = $dbSpool['tas_id']; } - if (empty($db_spool['pro_id'])) { + if (empty($dbSpool['pro_id'])) { $proId = isset($delegationIds['pro_id']) ? $delegationIds['pro_id'] : $appDelegation->getProcessId($appNumber); } else { - $proId = $db_spool['pro_id']; + $proId = $dbSpool['pro_id']; } $spool->setAppNumber($appNumber); @@ -706,6 +816,6 @@ class SpoolRun $spool->save(); } - return $sUID; + return $appMsgUid; } } diff --git a/workflow/engine/classes/WorkspaceTools.php b/workflow/engine/classes/WorkspaceTools.php index 611e5da25..2f37b70d2 100644 --- a/workflow/engine/classes/WorkspaceTools.php +++ b/workflow/engine/classes/WorkspaceTools.php @@ -2,13 +2,14 @@ use Illuminate\Database\QueryException; use Illuminate\Support\Facades\DB; +use ProcessMaker\BusinessModel\Process as BmProcess; /*----------------------------------********---------------------------------*/ use ProcessMaker\ChangeLog\ChangeLog; /*----------------------------------********---------------------------------*/ -use ProcessMaker\BusinessModel\Process as BmProcess; use ProcessMaker\Core\Installer; use ProcessMaker\Core\System; use ProcessMaker\Plugins\Adapters\PluginAdapter; +use ProcessMaker\Project\Adapter\BpmnWorkflow; use ProcessMaker\Util\FixReferencePath; /** @@ -2397,7 +2398,7 @@ class WorkspaceTools return; } - $arrayTable1 = ['ListInbox', 'ListMyInbox', 'ListCanceled', 'ListParticipatedLast', 'ListParticipatedHistory', 'ListPaused', 'ListCompleted']; + $arrayTable1 = ['ListInbox', 'ListMyInbox', 'ListCanceled', 'ListParticipatedLast', 'ListParticipatedHistory', 'ListPaused']; $arrayTable2 = ['ListUnassigned', 'ListUnassignedGroup']; $arrayTable = array_merge($arrayTable1, $arrayTable2); @@ -2423,7 +2424,6 @@ class WorkspaceTools } if ($flagReinsert || !$flagListAll) { - $this->regenerateListCompleted($lang); $this->regenerateListCanceled($lang); $this->regenerateListMyInbox(); //This list require no translation $this->regenerateListInbox(); //This list require no translation @@ -2508,69 +2508,6 @@ class WorkspaceTools CLI::logging("> Completed table LIST_CANCELED\n"); } - public function regenerateListCompleted($lang = 'en') - { - $this->initPropel(true); - $query = 'INSERT INTO ' . $this->dbName . '.LIST_COMPLETED - (APP_UID, - USR_UID, - TAS_UID, - PRO_UID, - APP_NUMBER, - APP_TITLE, - APP_PRO_TITLE, - APP_TAS_TITLE, - APP_CREATE_DATE, - APP_FINISH_DATE, - DEL_INDEX, - DEL_PREVIOUS_USR_UID, - DEL_CURRENT_USR_USERNAME, - DEL_CURRENT_USR_FIRSTNAME, - DEL_CURRENT_USR_LASTNAME) - - SELECT - ACV.APP_UID, - ACV.USR_UID, - ACV.TAS_UID, - ACV.PRO_UID, - ACV.APP_NUMBER, - C_APP.CON_VALUE AS APP_TITLE, - C_PRO.CON_VALUE AS APP_PRO_TITLE, - C_TAS.CON_VALUE AS APP_TAS_TITLE, - ACV.APP_CREATE_DATE, - ACV.APP_FINISH_DATE, - ACV.DEL_INDEX, - PREV_AD.USR_UID AS DEL_PREVIOUS_USR_UID, - USR.USR_USERNAME AS DEL_CURRENT_USR_USERNAME, - USR.USR_FIRSTNAME AS DEL_CURRENT_USR_FIRSTNAME, - USR.USR_LASTNAME AS DEL_CURRENT_USR_LASTNAME - FROM - (' . $this->dbName . '.APP_CACHE_VIEW ACV - LEFT JOIN ' . $this->dbName . '.CONTENT C_APP ON ACV.APP_UID = C_APP.CON_ID - AND C_APP.CON_CATEGORY = \'APP_TITLE\' - AND C_APP.CON_LANG = \'' . $lang . '\' - LEFT JOIN ' . $this->dbName . '.CONTENT C_PRO ON ACV.PRO_UID = C_PRO.CON_ID - AND C_PRO.CON_CATEGORY = \'PRO_TITLE\' - AND C_PRO.CON_LANG = \'' . $lang . '\' - LEFT JOIN ' . $this->dbName . '.CONTENT C_TAS ON ACV.TAS_UID = C_TAS.CON_ID - AND C_TAS.CON_CATEGORY = \'TAS_TITLE\' - AND C_TAS.CON_LANG = \'' . $lang . '\') - LEFT JOIN - (' . $this->dbName . '.APP_DELEGATION AD - INNER JOIN ' . $this->dbName . '.APP_DELEGATION PREV_AD ON AD.APP_UID = PREV_AD.APP_UID - AND AD.DEL_PREVIOUS = PREV_AD.DEL_INDEX) ON ACV.APP_UID = AD.APP_UID - AND ACV.DEL_INDEX = AD.DEL_INDEX - LEFT JOIN - ' . $this->dbName . '.USERS USR ON ACV.USR_UID = USR.USR_UID - WHERE - ACV.APP_STATUS = \'COMPLETED\' - AND ACV.DEL_LAST_INDEX = 1'; - $con = Propel::getConnection("workflow"); - $stmt = $con->createStatement(); - $stmt->executeQuery($query); - CLI::logging("> Completed table LIST_COMPLETED\n"); - } - public function regenerateListMyInbox() { $this->initPropel(true); @@ -3739,53 +3676,62 @@ class WorkspaceTools CLI::logging("|--> Clean data in table " . OauthRefreshTokensPeer::TABLE_NAME . " rows " . $refreshToken . "\n"); } + /** + * Migrate the Intermediate throw Email Event to Dummy task, specify the workspaces. + * The processes in this workspace will be updated. + * + * @param string $workspaceName + * @see workflow/engine/bin/tasks/cliWorkspaces.php::run_migrate_itee_to_dummytask() + * @see workflow/engine/classes/WorkspaceTools.php->upgradeDatabase() + * @link https://wiki.processmaker.com/3.3/processmaker_command#migrate-itee-to-dummytask + */ public function migrateIteeToDummytask($workspaceName) { $this->initPropel(true); - $arraySystemConfiguration = System::getSystemConfiguration('', '', $workspaceName); - $conf = new Configurations(); - \G::$sysSys = $workspaceName; - \G::$pathDataSite = PATH_DATA . "sites" . PATH_SEP . \G::$sysSys . PATH_SEP; - \G::$pathDocument = PATH_DATA . 'sites' . DIRECTORY_SEPARATOR . $workspaceName . DIRECTORY_SEPARATOR . 'files'; - \G::$memcachedEnabled = $arraySystemConfiguration['memcached']; - \G::$pathDataPublic = \G::$pathDataSite . "public" . PATH_SEP; - \G::$sysSkin = $conf->getConfiguration('SKIN_CRON', ''); - if (is_file(\G::$pathDataSite . PATH_SEP . ".server_info")) { - $serverInfo = file_get_contents(\G::$pathDataSite . PATH_SEP . ".server_info"); + $config = System::getSystemConfiguration('', '', $workspaceName); + G::$sysSys = $workspaceName; + G::$pathDataSite = PATH_DATA . "sites" . PATH_SEP . G::$sysSys . PATH_SEP; + G::$pathDocument = PATH_DATA . 'sites' . DIRECTORY_SEPARATOR . $workspaceName . DIRECTORY_SEPARATOR . 'files'; + G::$memcachedEnabled = $config['memcached']; + G::$pathDataPublic = G::$pathDataSite . "public" . PATH_SEP; + G::$sysSkin = $config['default_skin']; + if (is_file(G::$pathDataSite . PATH_SEP . ".server_info")) { + $serverInfo = file_get_contents(G::$pathDataSite . PATH_SEP . ".server_info"); $serverInfo = unserialize($serverInfo); $envHost = $serverInfo["SERVER_NAME"]; $envPort = ($serverInfo["SERVER_PORT"] . "" != "80") ? ":" . $serverInfo["SERVER_PORT"] : ""; if (!empty($envPort) && strpos($envHost, $envPort) === false) { $envHost = $envHost . $envPort; } - \G::$httpHost = $envHost; + G::$httpHost = $envHost; } //Search All process - $oCriteria = new Criteria("workflow"); - $oCriteria->addSelectColumn(ProcessPeer::PRO_UID); - $oCriteria->addSelectColumn(ProcessPeer::PRO_ITEE); - $oCriteria->add(ProcessPeer::PRO_ITEE, '0', Criteria::EQUAL); - $rsCriteria = ProcessPeer::doSelectRS($oCriteria); - $rsCriteria->setFetchmode(ResultSet::FETCHMODE_ASSOC); + $criteria = new Criteria("workflow"); + $criteria->addSelectColumn(ProcessPeer::PRO_UID); + $criteria->addSelectColumn(ProcessPeer::PRO_ITEE); + $criteria->add(ProcessPeer::PRO_ITEE, '0', Criteria::EQUAL); + $resultSet = ProcessPeer::doSelectRS($criteria); + $resultSet->setFetchmode(ResultSet::FETCHMODE_ASSOC); $message = "-> Migrating the Intermediate Email Event \n"; CLI::logging($message); - while ($rsCriteria->next()) { - $row = $rsCriteria->getRow(); - $prj_uid = $row['PRO_UID']; - $bpmnProcess = new Process(); - if ($bpmnProcess->isBpmnProcess($prj_uid)) { - $project = new \ProcessMaker\Project\Adapter\BpmnWorkflow(); - $diagram = $project->getStruct($prj_uid); - $res = $project->updateFromStruct($prj_uid, $diagram); - $bpmnProcess->setProUid($prj_uid); - $oProcess = new Process(); - $aProcess['PRO_UID'] = $prj_uid; - $aProcess['PRO_ITEE'] = '1'; - if ($oProcess->processExists($prj_uid)) { - $oProcess->update($aProcess); + while ($resultSet->next()) { + $row = $resultSet->getRow(); + $prjUid = $row['PRO_UID']; + $process = new Process(); + if ($process->isBpmnProcess($prjUid)) { + $project = new BpmnWorkflow(); + $diagram = $project->getStruct($prjUid); + $project->updateFromStruct($prjUid, $diagram); + $process->setProUid($prjUid); + $updateProcess = new Process(); + $updateProcessData = []; + $updateProcessData['PRO_UID'] = $prjUid; + $updateProcessData['PRO_ITEE'] = '1'; + if ($updateProcess->processExists($prjUid)) { + $updateProcess->update($updateProcessData); } - $message = " Process updated " . $bpmnProcess->getProTitle() . "\n"; + $message = " Process updated " . $process->getProTitle() . "\n"; CLI::logging($message); } } diff --git a/workflow/engine/classes/WsBase.php b/workflow/engine/classes/WsBase.php index ae157522c..ebea4bbe4 100644 --- a/workflow/engine/classes/WsBase.php +++ b/workflow/engine/classes/WsBase.php @@ -8,8 +8,19 @@ use ProcessMaker\Core\System; class WsBase { + const MESSAGE_TYPE_ACTIONS_BY_EMAIL = 'ACTIONS_BY_EMAIL'; + const MESSAGE_TYPE_CASE_NOTE = 'CASE_NOTE'; + const MESSAGE_TYPE_EMAIL_EVENT = 'EVENT'; + const MESSAGE_TYPE_EXTERNAL_REGISTRATION = 'EXTERNAL_REGISTRATION'; + const MESSAGE_TYPE_PM_FUNCTION = 'PM_FUNCTION'; + const MESSAGE_TYPE_RETRIEVE_PASSWORD = 'RETRIEVE_PASSWORD'; + const MESSAGE_TYPE_SOAP = 'SOAP'; + const MESSAGE_TYPE_TASK_NOTIFICATION = 'ROUTING'; + const MESSAGE_TYPE_TEST_EMAIL = 'TEST'; public $stored_system_variables; //boolean public $wsSessionId; //web service session id, if the wsbase function is used from a WS request + private $taskId; + private $flagSameCase = true; public function __construct($params = null) { @@ -22,6 +33,50 @@ class WsBase } } + /** + * Get the flagSameCase + * + * @return boolean + */ + public function getFlagSameCase() + { + return $this->flagSameCase; + } + + /** + * Set the flagSameCase + * + * @param boolean $var + * + * @return void + */ + public function setFlagSameCase($var) + { + $this->flagSameCase = $var; + } + + /** + * Get the taskId + * + * @return int + */ + public function getTaskId() + { + return $this->taskId; + } + + /** + * Set the taskId + * + * @param int $taskId + * + * @return void + */ + public function setTaskId($taskId) + { + $this->taskId = $taskId; + } + /** * function to start a web services session in ProcessMaker * @@ -831,6 +886,13 @@ class WsBase * @param array $config * * @return $result will return an object + * + * @see ActionsByEmailCoreClass->sendActionsByEmail() + * @see workflow\engine\classes\class.pmFunctions::PMFSendMessage() + * @see workflow\engine\methods\services\soap2::sendMessage() + * @see \ProcessMaker\BusinessModel\EmailEvent->sendEmail() + * @see \ProcessMaker\BusinessModel\Pmgmail->sendEmailWithApplicationData() + * */ public function sendMessage( $appUid, @@ -845,7 +907,8 @@ class WsBase $showMessage = true, $delIndex = 0, $config = [], - $gmail = 0 + $gmail = 0, + $appMsgType = WsBase::MESSAGE_TYPE_PM_FUNCTION ) { try { @@ -897,7 +960,7 @@ class WsBase $spool->setConfig($setup); $case = new Cases(); - $oldFields = $case->loadCase($appUid); + $oldFields = $case->loadCase($appUid, $delIndex); if ($gmail == 1) { $pathEmail = PATH_DATA_SITE . 'mailTemplates' . PATH_SEP; } else { @@ -923,11 +986,11 @@ class WsBase '', $appUid, $delIndex, - 'TRIGGER', + $appMsgType, $subject, G::buildFrom($setup, $from), $to, - G::replaceDataGridField(file_get_contents($fileTemplate), $fieldsCase, false), + G::replaceDataGridField(file_get_contents($fileTemplate), $fieldsCase, false, true), $cc, $bcc, '', @@ -938,7 +1001,7 @@ class WsBase (preg_match("/^.+\.html?$/i", $fileTemplate)) ? true : false, isset($fieldsCase['APP_NUMBER']) ? $fieldsCase['APP_NUMBER'] : 0, isset($fieldsCase['PRO_ID']) ? $fieldsCase['PRO_ID'] : 0, - isset($fieldsCase['TAS_ID']) ? $fieldsCase['TAS_ID'] : 0 + $this->getTaskId() ?$this->getTaskId():(isset($oldFields['TAS_ID'])? $oldFields['TAS_ID'] : 0) ); $spool->create($messageArray); @@ -1333,6 +1396,8 @@ class WsBase $result = new WsResponse(-1, G::LoadTranslation("ID_INVALID_DATA") . " $status"); return $result; + } else { + $status == 'INACTIVE' ? $RBAC->destroySessionUser($userUid) : null; } } @@ -2067,57 +2132,72 @@ class WsBase } /** - * creates a new case impersonating a user who has the proper privileges to create new cases + * Creates a new case impersonating a user who has the proper privileges to create new cases * * @param string $processId * @param string $userId - * @param string $variables - * @param string $taskId , must be in the starting group. + * @param array $variables, that are set in the new case + * @param string $taskId, must be in the starting group. * - * @return $result will return an object + * @return object + * + * @see PMFNewCaseImpersonate/class.pmFunctions.php on + * @link https://wiki.processmaker.com/3.1/ProcessMaker_Functions#PMFNewCaseImpersonate.28.29 + * + * @see doPostCaseImpersonate/Api/Cases on + * @link https://wiki.processmaker.com/3.2/REST_API_Cases/Cases#New_Case_Impersonate_User:_POST_.2Fcases.2Fimpersonate + * + * @see NewCaseImpersonate/soap2.php on + * @link https://wiki.processmaker.com/3.0/ProcessMaker_WSDL_Web_Services#newCaseImpersonate.28.29 */ public function newCaseImpersonate($processId, $userId, $variables, $taskId = '') { try { - if (is_array($variables)) { - if (count($variables) > 0) { - $c = count($variables); - $Fields = $variables; - } else { - if ($c == 0) { - $result = new WsResponse(10, G::loadTranslation('ID_ARRAY_VARIABLES_EMPTY')); + $g = new G(); + $g->sessionVarSave(); - return $result; - } + $c = count($variables); + if (is_array($variables)) { + if ($c > 0) { + $fieldsVariables = $variables; + } elseif ($c === 0) { + $result = new WsResponse(10, G::loadTranslation('ID_ARRAY_VARIABLES_EMPTY')); + $g->sessionVarRestore(); + + return $result; } } else { $result = new WsResponse(10, G::loadTranslation('ID_VARIABLES_PARAM_NOT_ARRAY')); + $g->sessionVarRestore(); return $result; } $processes = new Processes(); - if (!$processes->processExists($processId)) { $result = new WsResponse(11, G::loadTranslation('ID_INVALID_PROCESS') . " " . $processId . "!!"); + $g->sessionVarRestore(); return $result; } $user = new Users(); - if (!$user->userExists($userId)) { $result = new WsResponse(11, G::loadTranslation('ID_USER_NOT_REGISTERED') . " " . $userId . "!!"); + $g->sessionVarRestore(); return $result; + } else { + $user->load($userId); + $userName = $user->getUsrUsername(); } - $oCase = new Cases(); + $caseInstance = new Cases(); $numTasks = 0; - if ($taskId != '') { - $aTasks = $processes->getStartingTaskForUser($processId, null); - foreach ($aTasks as $task) { + if (!empty($taskId)) { + $startTasks = $processes->getStartingTaskForUser($processId, null); + foreach ($startTasks as $task) { if ($task['TAS_UID'] == $taskId) { $arrayTask[0]['TAS_UID'] = $taskId; $numTasks = 1; @@ -2128,38 +2208,47 @@ class WsBase $numTasks = count($arrayTask); } - if ($numTasks == 1) { - $case = $oCase->startCase($arrayTask[0]['TAS_UID'], $userId); - $caseId = $case['APPLICATION']; - $caseNumber = $case['CASE_NUMBER']; + if ($numTasks === 1) { + //@todo Find a better way to define session variables + $_SESSION["PROCESS"] = $processId; + $_SESSION["TASK"] = $arrayTask[0]['TAS_UID']; + $_SESSION["USER_LOGGED"] = $userId; + $_SESSION["INDEX"] = 1; + $_SESSION["USR_USERNAME"] = $userName; - $oldFields = $oCase->loadCase($caseId); - - $oldFields['APP_DATA'] = array_merge($oldFields['APP_DATA'], $Fields); - - $up_case = $oCase->updateCase($caseId, $oldFields); + //Create a newCase + $infoCase = $caseInstance->startCase($arrayTask[0]['TAS_UID'], $userId); + $_SESSION["APPLICATION"] = $caseId = $infoCase['APPLICATION']; + $oldFields = $caseInstance->loadCase($caseId); + //Merge the data with the $fieldsVariables that are set in the new case + $oldFields['APP_DATA'] = array_merge($oldFields['APP_DATA'], $fieldsVariables); + //Update the case + $res = $caseInstance->updateCase($caseId, $oldFields); $result = new WsResponse(0, G::loadTranslation('ID_COMMAND_EXECUTED_SUCCESSFULLY')); - $result->caseId = $caseId; - $result->caseNumber = $caseNumber; + $result->caseNumber = $infoCase['CASE_NUMBER']; + $g->sessionVarRestore(); return $result; } else { - if ($numTasks == 0) { + if ($numTasks === 0) { $result = new WsResponse(12, G::loadTranslation('ID_NO_STARTING_TASK')); + $g->sessionVarRestore(); return $result; } if ($numTasks > 1) { $result = new WsResponse(13, G::loadTranslation('ID_MULTIPLE_STARTING_TASKS')); + $g->sessionVarRestore(); return $result; } } } catch (Exception $e) { $result = new WsResponse(100, $e->getMessage()); + $g->sessionVarRestore(); return $result; } @@ -2178,6 +2267,8 @@ class WsBase * @param string $labelAssignment , label related to the triggerType * * @return string $varTriggers updated + * + * @see WsBase::derivateCase() */ public function executeTriggerFromDerivate( $appUid, @@ -2243,10 +2334,14 @@ class WsBase * * @param string $userId * @param string $caseId - * @param string $delIndex - * @param array $tasks + * @param integer $delIndex * @param bool $bExecuteTriggersBeforeAssignment + * @param array $tasks + * * @return $result will return an object + * + * @see PMFDerivateCase()/class.pmFunctions.php on + * @link https://wiki.processmaker.com/3.2/ProcessMaker_Functions/Case_Routing_Functions#PMFDerivateCase.28.29 */ public function derivateCase($userId, $caseId, $delIndex, $bExecuteTriggersBeforeAssignment = false, $tasks = []) { @@ -3061,6 +3156,10 @@ class WsBase public function cancelCase($caseUid, $delIndex, $userUid) { $g = new G(); + //We will to review if the current case in execution will be execute the same + if (isset($_SESSION["APPLICATION"]) && $_SESSION["APPLICATION"] !== $caseUid){ + $this->setFlagSameCase(false); + } try { $g->sessionVarSave(); @@ -3086,7 +3185,7 @@ class WsBase /** If those parameters are null we will to force the cancelCase */ if (is_null($delIndex) && is_null($userUid)) { /*----------------------------------********---------------------------------*/ - $case->cancelCase($caseUid, null, null); + $case->cancelCase($caseUid, null, null, $this->getFlagSameCase()); $result = self::messageExecuteSuccessfully(); $g->sessionVarRestore(); @@ -3123,7 +3222,7 @@ class WsBase /** Cancel case */ - $case->cancelCase($caseUid, (int)$delIndex, $userUid); + $case->cancelCase($caseUid, (int)$delIndex, $userUid, $this->getFlagSameCase()); //Define the result of the cancelCase $result = self::messageExecuteSuccessfully(); @@ -3146,7 +3245,12 @@ class WsBase * @param string userUid : The unique ID of the user who will pause the case. * @param string unpauseDate : Optional parameter. The date in the format "yyyy-mm-dd" indicating when to unpause * the case. - * + * + * @see workflow/engine/classes/class.pmFunctions.php::PMFPauseCase() + * @see workflow/engine/methods/services/soap2.php::pauseCase() + * + * @link https://wiki.processmaker.com/3.3/ProcessMaker_Functions/Case_Functions#PMFPauseCase.28.29 + * * @return $result will return an object */ public function pauseCase($caseUid, $delIndex, $userUid, $unpauseDate = null) @@ -3182,6 +3286,22 @@ class WsBase return $result; } + //Validate if status is closed + $appDelegation = new AppDelegation(); + $rows = $appDelegation->LoadParallel($caseUid, $delIndex); + if (empty($rows)) { + $result = new WsResponse(100, G::LoadTranslation('ID_CASE_DELEGATION_ALREADY_CLOSED')); + $g->sessionVarRestore(); + return $result; + } + //Validate if the case is paused + $appDelay = new AppDelay(); + $sw = $appDelay->isPaused($caseUid, $delIndex); + if ($sw === true) { + $result = new WsResponse(19, G::LoadTranslation('ID_CASE_IN_STATUS') . " " . AppDelay::APP_TYPE_PAUSE); + $g->sessionVarRestore(); + return $result; + } if (strlen($unpauseDate) >= 10) { if (!preg_match("/^\d{4}-\d{2}-\d{2}| \d{2}:\d{2}:\d{2}$/", $unpauseDate)) { $result = new WsResponse(100, G::LoadTranslation("ID_INVALID_DATA") . " $unpauseDate"); diff --git a/workflow/engine/classes/class.pmFunctions.php b/workflow/engine/classes/class.pmFunctions.php index 8d1fb765b..31cf411a4 100644 --- a/workflow/engine/classes/class.pmFunctions.php +++ b/workflow/engine/classes/class.pmFunctions.php @@ -28,11 +28,11 @@ // // License: LGPL, see LICENSE //////////////////////////////////////////////////// +use ProcessMaker\BusinessModel\Cases as BusinessModelCases; use ProcessMaker\Core\System; use ProcessMaker\Plugins\PluginRegistry; use ProcessMaker\Util\ElementTranslation; - /** * ProcessMaker has made a number of its PHP functions available be used in triggers and conditions. * Most of these functions are wrappers for internal functions used in Gulliver, which is the development framework @@ -920,34 +920,34 @@ function getEmailConfiguration () * @link http://wiki.processmaker.com/index.php/ProcessMaker_Functions#PMFSendMessage.28.29 * * @param string(32) | $caseId | UID for case | The UID (unique identification) for a case, which is a string of 32 hexadecimal characters to identify the case. - * @param string(32) | $sFrom | Sender | The email address of the person who sends out the email. - * @param string(100) | $sTo | Recipient | The email address(es) to whom the email is sent. If multiple recipients, separate each email address with a comma. - * @param string(100) | $sCc = '' | Carbon copy recipient | The email address(es) of people who will receive carbon copies of the email. - * @param string(100) | $sBcc = ''| Carbon copy recipient | The email address(es) of people who will receive blind carbon copies of the email. - * @param string(50) | $sSubject | Subject of the email | The subject (title) of the email. - * @param string(50) | $sTemplate | Name of the template | The name of the template file in plain text or HTML format which will produce the body of the email. - * @param array | $aFields = array() | Variables for email template | Optional parameter. An associative array where the keys are the variable names and the values are the variables' values. - * @param array | $aAttachment = array() | Attachment | An Optional arrray. An array of files (full paths) to be attached to the email. + * @param string(32) | $from | Sender | The email address of the person who sends out the email. + * @param string(100) | $to | Recipient | The email address(es) to whom the email is sent. If multiple recipients, separate each email address with a comma. + * @param string(100) | $cc = '' | Carbon copy recipient | The email address(es) of people who will receive carbon copies of the email. + * @param string(100) | $bcc = ''| Carbon copy recipient | The email address(es) of people who will receive blind carbon copies of the email. + * @param string(50) | $subject | Subject of the email | The subject (title) of the email. + * @param string(50) | $template | Name of the template | The name of the template file in plain text or HTML format which will produce the body of the email. + * @param array | $emailTemplateVariables = [] | Variables for email template | Optional parameter. An associative array where the keys are the variable names and the values are the variables' values. + * @param array | $attachments = [] | Attachment | An Optional arrray. An array of files (full paths) to be attached to the email. * @param boolean | $showMessage = true | Show message | Optional parameter. Set to TRUE to show the message in the case's message history. * @param int | $delIndex = 0 | Delegation index of the case | Optional parameter. The delegation index of the current task in the case. - * @param string(100) | $config = '' | Email server configuration | An optional array: An array of parameters to be used in the Email sent (MESS_ENGINE, MESS_SERVER, MESS_PORT, MESS_FROM_MAIL, MESS_RAUTH, MESS_ACCOUNT, MESS_PASSWORD, and SMTPSecure) Or String: UID of Email server . + * @param array | $config = [] | Email server configuration | An optional array: An array of parameters to be used in the Email sent (MESS_ENGINE, MESS_SERVER, MESS_PORT, MESS_FROM_MAIL, MESS_RAUTH, MESS_ACCOUNT, MESS_PASSWORD, and SMTPSecure) Or String: UID of Email server . * @return int | | result | Result of sending email * + * @see class.pmFunctions::PMFSendMessageToGroup() */ -//@param array | $aFields=array() | An associative array optional | Optional parameter. An associative array where the keys are the variable name and the values are the variable's value. function PMFSendMessage( $caseId, - $sFrom, - $sTo, - $sCc, - $sBcc, - $sSubject, - $sTemplate, - $aFields = array(), - $aAttachment = array(), + $from, + $to, + $cc, + $bcc, + $subject, + $template, + $emailTemplateVariables = [], + $attachments = [], $showMessage = true, $delIndex = 0, - $config = array() + $config = [] ) { ini_set ( "pcre.backtrack_limit", 1000000 ); ini_set ( 'memory_limit', '-1' ); @@ -955,28 +955,30 @@ function PMFSendMessage( global $oPMScript; - if (isset( $oPMScript->aFields ) && is_array( $oPMScript->aFields )) { - if (is_array( $aFields )) { - $aFields = array_merge( $oPMScript->aFields, $aFields ); + if (isset($oPMScript->aFields) && is_array($oPMScript->aFields)) { + if (is_array($emailTemplateVariables)) { + $emailTemplateVariables = array_merge($oPMScript->aFields, $emailTemplateVariables); } else { - $aFields = $oPMScript->aFields; + $emailTemplateVariables = $oPMScript->aFields; } } $ws = new WsBase(); $result = $ws->sendMessage( $caseId, - $sFrom, - $sTo, - $sCc, - $sBcc, - $sSubject, - $sTemplate, - $aFields, - $aAttachment, + $from, + $to, + $cc, + $bcc, + $subject, + $template, + $emailTemplateVariables, + $attachments, $showMessage, $delIndex, - $config + $config, + 0, + WsBase::MESSAGE_TYPE_PM_FUNCTION ); if ($result->status_code == 0) { @@ -2825,7 +2827,7 @@ function PMFPauseCase ($caseUid, $delIndex, $userUid, $unpauseDate = null) { $ws = new WsBase(); $result = $ws->pauseCase($caseUid, $delIndex, $userUid, $unpauseDate); - + $result = (object) $result; if ($result->status_code == 0) { if (isset($_SESSION['APPLICATION']) && isset($_SESSION['INDEX'])) { if ($_SESSION['APPLICATION'] == $caseUid && $_SESSION['INDEX'] == $delIndex) { @@ -3470,38 +3472,26 @@ function PMFGetNextDerivationInfo($caseUid, $delIndex) * @param string | $skin = null | Skin | The skin * * @return string | $url | Direct case link | Returns the direct case link, FALSE otherwise + * @link https://wiki.processmaker.com/3.2/Direct_Case_Link */ function PMFCaseLink($caseUid, $workspace = null, $language = null, $skin = null) { try { - $case = new \ProcessMaker\BusinessModel\Cases(); - + $case = new BusinessModelCases(); $arrayApplicationData = $case->getApplicationRecordByPk($caseUid, [], false); - if ($arrayApplicationData === false) { return false; } - $conf = new Configurations(); - $envSkin = defined("SYS_SKIN") ? SYS_SKIN : $conf->getConfiguration('SKIN_CRON', ''); - $workspace = (!empty($workspace)) ? $workspace : config("system.workspace"); - $language = (!empty($language)) ? $language : SYS_LANG; - $skin = (!empty($skin)) ? $skin : $envSkin; + + $workspace = !empty($workspace) ? $workspace : config("system.workspace"); + $language = !empty($language) ? $language : SYS_LANG; + if (empty($skin)) { + $config = System::getSystemConfiguration(); + $skin = defined("SYS_SKIN") ? SYS_SKIN : $config['default_skin']; + } $uri = '/sys' . $workspace . '/' . $language . '/' . $skin . '/cases/opencase/' . $caseUid; - - $envHost = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : SERVER_NAME; - $envProtocol = defined("REQUEST_SCHEME") && REQUEST_SCHEME === "https"; - if (isset($_SERVER['SERVER_PORT'])) { - $envPort = ($_SERVER['SERVER_PORT'] != "80") ? ":" . $_SERVER['SERVER_PORT'] : ""; - } else if (defined('SERVER_PORT')) { - $envPort = (SERVER_PORT . "" != "80") ? ":" . SERVER_PORT : ""; - } else { - $envPort = ""; - } - if (!empty($envPort) && strpos($envHost, $envPort) === false) { - $envHost = $envHost . $envPort; - } - $link = (G::is_https() || $envProtocol ? 'https://' : 'http://') . $envHost . $uri; + $link = System::getServerProtocolHost() . $uri; return $link; } catch (Exception $e) { throw $e; diff --git a/workflow/engine/classes/class.pmScript.php b/workflow/engine/classes/class.pmScript.php index 83585e2d5..cd4cf8631 100644 --- a/workflow/engine/classes/class.pmScript.php +++ b/workflow/engine/classes/class.pmScript.php @@ -281,15 +281,22 @@ class PMScript self::AFTER_EXTERNAL_STEP : self::UNDEFINED_ORIGIN; break; case 'ASSIGN_TASK': + $stepUidObj = (int)$stepUidObj; if ($stepUidObj === -1) { $executedOn = $triggerType === 'BEFORE' ? self::BEFORE_ASSIGNMENT : self::UNDEFINED_ORIGIN; } elseif ($stepUidObj === -2) { - $executedOn = $triggerType === 'BEFORE' ? self::BEFORE_ROUTING : $triggerType === 'AFTER' ? - self::AFTER_ROUTING : self::UNDEFINED_ORIGIN; + $executedOn = $triggerType === 'BEFORE' ? self::BEFORE_ROUTING : ($triggerType === 'AFTER' ? + self::AFTER_ROUTING : self::UNDEFINED_ORIGIN); } else { $executedOn = self::UNDEFINED_ORIGIN; } break; + case 'PROCESS_ACTION': + $executedOn = self::PROCESS_ACTION; + break; + case 'SCRIPT_TASK': + $executedOn = self::SCRIPT_TASK; + break; default: $executedOn = self::UNDEFINED_ORIGIN; break; @@ -304,7 +311,7 @@ class PMScript public function executeAndCatchErrors($sScript, $sCode) { ob_start('handleFatalErrors'); - set_error_handler('handleErrors'); + set_error_handler('handleErrors', ini_get('error_reporting')); $_SESSION['_CODE_'] = $sCode; $_SESSION['_DATA_TRIGGER_'] = $this->dataTrigger; $_SESSION['_DATA_TRIGGER_']['_EXECUTION_TIME_'] = microtime(true); @@ -464,6 +471,8 @@ class PMScript $sScript = "try {\n" . $sScript . "\n} catch (Exception \$oException) {\n " . " \$this->aFields['__ERROR__'] = utf8_encode(\$oException->getMessage());\n}"; $this->executeAndCatchErrors($sScript, $this->sScript); + //We get the affected_fields only if has the prefix + //@see https://wiki.processmaker.com/3.2/Triggers#Typing_rules_for_Case_Variables $this->setVarsChanged($this->affected_fields); $this->aFields["__VAR_CHANGED__"] = implode(",", $this->affected_fields); for ($i = 0; $i < count($this->affected_fields); $i ++) { diff --git a/workflow/engine/classes/class.webdav.php b/workflow/engine/classes/class.webdav.php index 4fd290379..d4d9503d6 100644 --- a/workflow/engine/classes/class.webdav.php +++ b/workflow/engine/classes/class.webdav.php @@ -944,6 +944,8 @@ class ProcessMakerWebDav extends HTTP_WebDAV_Server * * @param string resource path to check for locks * @return bool true on success + * @link https://wiki.processmaker.com/index.php/WebDAV + * @deprecated */ public function checkLock($path) { @@ -959,7 +961,9 @@ class ProcessMakerWebDav extends HTTP_WebDAV_Server if ($res) { $row = mysqli_fetch_array($res); - mysqli_free_result($res); + if (is_resource($res)) { + mysqli_free_result($res); + } if ($row) { $result = array("type" => "write", "scope" => $row["exclusivelock"] ? "exclusive" : "shared", "depth" => 0, "owner" => $row['owner'], "token" => $row['token'], "expires" => $row['expires'] diff --git a/workflow/engine/classes/model/AbeConfiguration.php b/workflow/engine/classes/model/AbeConfiguration.php index 6b740d85a..66b6cf0d0 100644 --- a/workflow/engine/classes/model/AbeConfiguration.php +++ b/workflow/engine/classes/model/AbeConfiguration.php @@ -48,6 +48,17 @@ class AbeConfiguration extends BaseAbeConfiguration } } + /** + * Create or update. + * + * @param array $data + * @throws Exception + * + * @see Processes->createActionsByEmail() + * @see ProcessMaker\BusinessModel\ActionsByEmail->saveConfiguration() + * @see ProcessMaker\BusinessModel\ActionsByEmail->saveConfiguration2() + * @link https://wiki.processmaker.com/3.3/Actions_by_Email#Configuration + */ public function createOrUpdate($data) { foreach ($data as $field => $value) { @@ -70,6 +81,11 @@ class AbeConfiguration extends BaseAbeConfiguration } else { $abeConfigurationInstance = AbeConfigurationPeer::retrieveByPK($data['ABE_UID']); } + //Only the 'FIELD' and 'LINK' types have a DYN_UID, + //the DYN_UID field is empty when the type is 'CUSTOM'. + if ($data['ABE_TYPE'] === 'CUSTOM') { + $data['DYN_UID'] = ''; + } if (isset($data['ABE_CUSTOM_GRID'])) { $data['ABE_CUSTOM_GRID'] = serialize($data['ABE_CUSTOM_GRID']); diff --git a/workflow/engine/classes/model/AppAssignSelfServiceValue.php b/workflow/engine/classes/model/AppAssignSelfServiceValue.php index b2fea9d9b..07a68e6ab 100644 --- a/workflow/engine/classes/model/AppAssignSelfServiceValue.php +++ b/workflow/engine/classes/model/AppAssignSelfServiceValue.php @@ -64,6 +64,12 @@ class AppAssignSelfServiceValue extends BaseAppAssignSelfServiceValue * * @return void * @throws Exception + * + * @see \Cases->removeCase() + * @see \Cases->setCatchUser() + * @see \Cases->updateCase() + * + * @link https://wiki.processmaker.com/3.2/Tasks#Self_Service_Value_Based_Assignment */ public function remove($applicationUid, $delIndex = 0) { @@ -76,18 +82,7 @@ class AppAssignSelfServiceValue extends BaseAppAssignSelfServiceValue $criteria->add(AppAssignSelfServiceValuePeer::DEL_INDEX, $delIndex, Criteria::EQUAL); } - $result = AppAssignSelfServiceValuePeer::doDelete($criteria); - - // Delete related rows and missing relations, criteria don't execute delete with joins - $cnn = Propel::getConnection(AppAssignSelfServiceValueGroupPeer::DATABASE_NAME); - $cnn->begin(); - $stmt = $cnn->createStatement(); - $rs = $stmt->executeQuery("DELETE " . AppAssignSelfServiceValueGroupPeer::TABLE_NAME . " - FROM " . AppAssignSelfServiceValueGroupPeer::TABLE_NAME . " - LEFT JOIN " . AppAssignSelfServiceValuePeer::TABLE_NAME . " - ON (" . AppAssignSelfServiceValueGroupPeer::ID . " = " . AppAssignSelfServiceValuePeer::ID . ") - WHERE " . AppAssignSelfServiceValuePeer::ID . " IS NULL"); - $cnn->commit(); + AppAssignSelfServiceValuePeer::doDelete($criteria); } catch (Exception $e) { throw $e; } diff --git a/workflow/engine/classes/model/AppDelegation.php b/workflow/engine/classes/model/AppDelegation.php index d47790a7e..39977faca 100644 --- a/workflow/engine/classes/model/AppDelegation.php +++ b/workflow/engine/classes/model/AppDelegation.php @@ -223,7 +223,6 @@ class AppDelegation extends BaseAppDelegation try { $res = $this->save(); } catch (PropelException $e) { - error_log($e->getMessage()); return; } } else { @@ -1046,4 +1045,45 @@ class AppDelegation extends BaseAppDelegation return $delIndex; } + + /** + * Update the priority in AppDelegation table, using the defined variable in task + * + * @param integer $delIndex + * @param string $tasUid + * @param string $appUid + * @param array $fieldAppData + * + * @return void + * + * @see Cases->update() + * + */ + public function updatePriority($delIndex, $tasUid, $appUid, $fieldAppData) + { + if (!empty($delIndex) && !empty($tasUid)) { + //Optimized code to avoid load task content row. + $criteria = new Criteria(); + $criteria->clearSelectColumns(); + $criteria->addSelectColumn(TaskPeer::TAS_PRIORITY_VARIABLE); + $criteria->add(TaskPeer::TAS_UID, $tasUid); + $rs = TaskPeer::doSelectRS($criteria); + $rs->setFetchmode(ResultSet::FETCHMODE_ASSOC); + $rs->next(); + $row = $rs->getRow(); + $tasPriority = substr($row['TAS_PRIORITY_VARIABLE'], 2); + //End optimized code. + + $x = $fieldAppData; + if (!empty($x[$tasPriority])) { + $array = []; + $array['APP_UID'] = $appUid; + $array['DEL_INDEX'] = $delIndex; + $array['TAS_UID'] = $tasUid; + $array['DEL_PRIORITY'] = (isset($x[$tasPriority]) ? + ($x[$tasPriority] >= 1 && $x[$tasPriority] <= 5 ? $x[$tasPriority] : '3') : '3'); + $this->update($array); + } + } + } } diff --git a/workflow/engine/classes/model/AppMessage.php b/workflow/engine/classes/model/AppMessage.php index 90f1fc9a4..8758937b3 100644 --- a/workflow/engine/classes/model/AppMessage.php +++ b/workflow/engine/classes/model/AppMessage.php @@ -160,7 +160,7 @@ class AppMessage extends BaseAppMessage * @param string $appMsgTemplate, * @param string $appMsgAttach, * @param string $appMsgStatus, - * @param string $appMsgShowMsg, + * @param integer $appMsgShowMsg, * @param string $appMsgError, * @param boolean $contentTypeIsHtml * @param integer $appNumber, @@ -183,7 +183,7 @@ class AppMessage extends BaseAppMessage $appMsgTemplate = '', $appMsgAttach = '', $appMsgStatus = 'pending', - $appMsgShowMsg = '', + $appMsgShowMsg = 1, $appMsgError = '', $contentTypeIsHtml = true, $appNumber = 0, diff --git a/workflow/engine/classes/model/AppNotes.php b/workflow/engine/classes/model/AppNotes.php index 57db63a23..a36b13681 100644 --- a/workflow/engine/classes/model/AppNotes.php +++ b/workflow/engine/classes/model/AppNotes.php @@ -1,7 +1,7 @@ getCaseNotes() + * @see \AppProxy->getNotesList() + * @see \Home->getAppsData() + * @see workflow/engine/methods/cases/caseNotesAjax.php->getNotesList() + * @see \ProcessMaker\BusinessModel\Cases->getCaseNotes() + * @see \ProcessMaker\Services\Api\Light->doGetCaseNotes() + * + * @link https://wiki.processmaker.com/3.2/Case_Notes#Viewing_Existing_Case_Notes + */ + public function getNotesList( $appUid, $usrUid = '', $start = '', @@ -25,70 +50,71 @@ class AppNotes extends BaseAppNotes $dir = 'DESC', $dateFrom = '', $dateTo = '', - $search = '') - { - $Criteria = new Criteria( 'workflow' ); - $Criteria->clearSelectColumns(); + $search = '' + ) { + $criteria = new Criteria('workflow'); + $criteria->clearSelectColumns(); - $Criteria->addSelectColumn( AppNotesPeer::APP_UID ); - $Criteria->addSelectColumn( AppNotesPeer::USR_UID ); - $Criteria->addSelectColumn( AppNotesPeer::NOTE_DATE ); - $Criteria->addSelectColumn( AppNotesPeer::NOTE_CONTENT ); - $Criteria->addSelectColumn( AppNotesPeer::NOTE_TYPE ); - $Criteria->addSelectColumn( AppNotesPeer::NOTE_AVAILABILITY ); - $Criteria->addSelectColumn( AppNotesPeer::NOTE_ORIGIN_OBJ ); - $Criteria->addSelectColumn( AppNotesPeer::NOTE_AFFECTED_OBJ1 ); - $Criteria->addSelectColumn( AppNotesPeer::NOTE_AFFECTED_OBJ2 ); - $Criteria->addSelectColumn( AppNotesPeer::NOTE_RECIPIENTS ); - $Criteria->addSelectColumn( UsersPeer::USR_USERNAME ); - $Criteria->addSelectColumn( UsersPeer::USR_FIRSTNAME ); - $Criteria->addSelectColumn( UsersPeer::USR_LASTNAME ); - $Criteria->addSelectColumn( UsersPeer::USR_EMAIL ); + $criteria->addSelectColumn(AppNotesPeer::APP_UID); + $criteria->addSelectColumn(AppNotesPeer::USR_UID); + $criteria->addSelectColumn(AppNotesPeer::NOTE_DATE); + $criteria->addSelectColumn(AppNotesPeer::NOTE_CONTENT); + $criteria->addSelectColumn(AppNotesPeer::NOTE_TYPE); + $criteria->addSelectColumn(AppNotesPeer::NOTE_AVAILABILITY); + $criteria->addSelectColumn(AppNotesPeer::NOTE_ORIGIN_OBJ); + $criteria->addSelectColumn(AppNotesPeer::NOTE_AFFECTED_OBJ1); + $criteria->addSelectColumn(AppNotesPeer::NOTE_AFFECTED_OBJ2); + $criteria->addSelectColumn(AppNotesPeer::NOTE_RECIPIENTS); + $criteria->addSelectColumn(UsersPeer::USR_USERNAME); + $criteria->addSelectColumn(UsersPeer::USR_FIRSTNAME); + $criteria->addSelectColumn(UsersPeer::USR_LASTNAME); + $criteria->addSelectColumn(UsersPeer::USR_EMAIL); - $Criteria->addJoin( AppNotesPeer::USR_UID, UsersPeer::USR_UID, Criteria::LEFT_JOIN ); + $criteria->addJoin(AppNotesPeer::USR_UID, UsersPeer::USR_UID, Criteria::LEFT_JOIN); - $Criteria->add( AppNotesPeer::APP_UID, $appUid, Criteria::EQUAL ); + $criteria->add(AppNotesPeer::APP_UID, $appUid, Criteria::EQUAL); if ($usrUid != '') { - $Criteria->add( AppNotesPeer::USR_UID, $usrUid, Criteria::EQUAL ); + $criteria->add(AppNotesPeer::USR_UID, $usrUid, Criteria::EQUAL); } if ($dateFrom != '') { - $Criteria->add( AppNotesPeer::NOTE_DATE, $dateFrom, Criteria::GREATER_EQUAL ); + $criteria->add(AppNotesPeer::NOTE_DATE, $dateFrom, Criteria::GREATER_EQUAL); } if ($dateTo != '') { - $Criteria->add( AppNotesPeer::NOTE_DATE, $dateTo, Criteria::LESS_EQUAL ); + $criteria->add(AppNotesPeer::NOTE_DATE, $dateTo, Criteria::LESS_EQUAL); } if ($search != '') { - $Criteria->add( AppNotesPeer::NOTE_CONTENT, '%'.$search.'%', Criteria::LIKE ); + $criteria->add(AppNotesPeer::NOTE_CONTENT, '%' . $search . '%', Criteria::LIKE); } if ($dir == 'DESC') { - $Criteria->addDescendingOrderByColumn($sort); + $criteria->addDescendingOrderByColumn($sort); } else { - $Criteria->addAscendingOrderByColumn($sort); + $criteria->addAscendingOrderByColumn($sort); } - $response = array (); - $totalCount = AppNotesPeer::doCount( $Criteria ); + $response = []; + $totalCount = AppNotesPeer::doCount($criteria); $response['totalCount'] = $totalCount; - $response['notes'] = array (); + $response['notes'] = []; if ($start != '') { - $Criteria->setLimit( $limit ); - $Criteria->setOffset( $start ); + $criteria->setLimit($limit); + $criteria->setOffset($start); } - $oDataset = appNotesPeer::doSelectRS( $Criteria ); - $oDataset->setFetchmode( ResultSet::FETCHMODE_ASSOC ); - $oDataset->next(); + $dataset = AppNotesPeer::doSelectRS($criteria); + $dataset->setFetchmode(ResultSet::FETCHMODE_ASSOC); + $dataset->next(); - while ($aRow = $oDataset->getRow()) { - $aRow['NOTE_CONTENT'] = stripslashes($aRow['NOTE_CONTENT']); - $response['notes'][] = $aRow; - $oDataset->next(); + while ($row = $dataset->getRow()) { + $row['NOTE_CONTENT'] = stripslashes($row['NOTE_CONTENT']); + $response['notes'][] = $row; + $dataset->next(); } - $result['criteria'] = $Criteria; + $result = []; + $result['criteria'] = $criteria; $result['array'] = $response; return $result; @@ -154,8 +180,12 @@ class AppNotes extends BaseAppNotes * @param string $noteRecipients * @param string $from * @param integer $delIndex - * + * @return void * @throws Exception + * + * @see AppNotes->addCaseNote() + * @see AppNotes->postNewNote() + * @see workflow/engine/src/ProcessMaker/Util/helpers.php::postNote() */ public function sendNoteNotification ($appUid, $usrUid, $noteContent, $noteRecipients, $from = '', $delIndex = 0) { @@ -169,9 +199,14 @@ class AppNotes extends BaseAppNotes $configuration['MESS_ENGINE'] = ''; } - $users = new Users(); - $userInfo = $users->load($usrUid); - $authorName = ((($userInfo['USR_FIRSTNAME'] != '') || ($userInfo['USR_LASTNAME'] != '')) ? $userInfo['USR_FIRSTNAME'] . ' ' . $userInfo['USR_LASTNAME'] . ' ' : '') . '<' . $userInfo['USR_EMAIL'] . '>'; + //This value can be empty when the previous task is: 'Script Task', 'Timer Event' or other without user. + if (!empty($usrUid)) { + $users = new Users(); + $userInfo = $users->load($usrUid); + $authorName = ((($userInfo['USR_FIRSTNAME'] != '') || ($userInfo['USR_LASTNAME'] != '')) ? $userInfo['USR_FIRSTNAME'] . ' ' . $userInfo['USR_LASTNAME'] . ' ' : '') . '<' . $userInfo['USR_EMAIL'] . '>'; + } else { + $authorName = G::LoadTranslation('UID_UNDEFINED_USER'); + } $cases = new Cases(); $fieldCase = $cases->loadCase($appUid, $delIndex); @@ -193,7 +228,7 @@ class AppNotes extends BaseAppNotes '', $appUid, $delIndex, - 'DERIVATION', + WsBase::MESSAGE_TYPE_CASE_NOTE, G::replaceDataField($configNoteNotification['subject'], $fieldCase), G::buildFrom($configuration, $from), $to, @@ -203,7 +238,7 @@ class AppNotes extends BaseAppNotes '', '', 'pending', - '', + 1, $msgError, true, (isset($fieldCase['APP_NUMBER'])) ? $fieldCase['APP_NUMBER'] : 0, diff --git a/workflow/engine/classes/model/Dynaform.php b/workflow/engine/classes/model/Dynaform.php index f1053c0ac..89979a570 100644 --- a/workflow/engine/classes/model/Dynaform.php +++ b/workflow/engine/classes/model/Dynaform.php @@ -223,14 +223,8 @@ class Dynaform extends BaseDynaform $description = "Create from a PM Table: " . $addTabName . ", "; } G::auditLog("CreateDynaform", $description . "Dynaform Title: " . $aData['DYN_TITLE'] . ", Type: " . $aData['DYN_TYPE'] . ", Description: " . $aData['DYN_DESCRIPTION'] . ", Mode: " . $mode); - - $sXml = '' . "\n"; - $sXml .= '' . "\n"; - $sXml .= ''; - G::verifyPath(PATH_DYNAFORM . $this->getProUid(), true); - $oFile = fopen(PATH_DYNAFORM . $this->getProUid() . '/' . $this->getDynUid() . '.xml', 'w'); - fwrite($oFile, $sXml); - fclose($oFile); + + Form::createXMLFile($this->getProUid(), $this->getDynUid(), $this->getDynType(), PATH_DYNAFORM); return $this->getDynUid(); } else { $msg = ''; diff --git a/workflow/engine/classes/model/Groupwf.php b/workflow/engine/classes/model/Groupwf.php index 989c0fca2..d14583f10 100644 --- a/workflow/engine/classes/model/Groupwf.php +++ b/workflow/engine/classes/model/Groupwf.php @@ -98,13 +98,13 @@ class Groupwf extends BaseGroupwf $this->setGrpTitle('Default Group Title'); } - if (!empty($aData['GRP_STATUS'])) { + if (!empty($data['GRP_STATUS'])) { $this->setGrpStatus($data['GRP_STATUS']); } else { $this->setGrpStatus('ACTIVE'); } - if (!empty($aData['GRP_LDAP_DN'])) { + if (!empty($data['GRP_LDAP_DN'])) { $this->setGrpLdapDn($data['GRP_LDAP_DN']); } else { $this->setGrpLdapDn(''); diff --git a/workflow/engine/classes/model/ListCompleted.php b/workflow/engine/classes/model/ListCompleted.php index d7c145657..d8c88ef5f 100644 --- a/workflow/engine/classes/model/ListCompleted.php +++ b/workflow/engine/classes/model/ListCompleted.php @@ -13,8 +13,8 @@ require_once 'classes/model/om/BaseListCompleted.php'; * long as it does not already exist in the output directory. * * @package classes.model + * @deprecated Method deprecated in Release 3.3.9 */ -// @codingStandardsIgnoreStart class ListCompleted extends BaseListCompleted implements ListInterface { use ListBaseTrait; diff --git a/workflow/engine/classes/model/ListParticipatedLast.php b/workflow/engine/classes/model/ListParticipatedLast.php index 587d4a21a..1df4db269 100644 --- a/workflow/engine/classes/model/ListParticipatedLast.php +++ b/workflow/engine/classes/model/ListParticipatedLast.php @@ -1,6 +1,7 @@ add(ListParticipatedLastPeer::APP_UID, $appUid, Criteria::EQUAL); + //Update - SET + $criteriaSet = new Criteria("workflow"); + $criteriaSet->add(ListParticipatedLastPeer::APP_STATUS, $status); + BasePeer::doUpdate($criteriaWhere, $criteriaSet, Propel::getConnection("workflow")); + } } diff --git a/workflow/engine/classes/model/ListUnassigned.php b/workflow/engine/classes/model/ListUnassigned.php index 7306ad7fe..a073a8c7b 100644 --- a/workflow/engine/classes/model/ListUnassigned.php +++ b/workflow/engine/classes/model/ListUnassigned.php @@ -333,18 +333,16 @@ class ListUnassigned extends BaseListUnassigned implements ListInterface { try { $arrayAppAssignSelfServiceValueData = []; - $criteria = new Criteria("workflow"); + $group = new Groups(); + //Get the GRP_ID related to the $userUid + $arrayId = $group->getActiveGroupsForAnUserById($userUid); + $sql = "(" - . AppAssignSelfServiceValueGroupPeer::ASSIGNEE_ID . " IN (" - . " SELECT " . GroupUserPeer::GRP_ID . " " - . " FROM " . GroupUserPeer::TABLE_NAME . " " - . " LEFT JOIN " . GroupwfPeer::TABLE_NAME . " ON (" . GroupUserPeer::GRP_ID . "=" . GroupwfPeer::GRP_ID . ") " - . " WHERE " . GroupUserPeer::USR_UID . "='" . $userUid . "' AND " . GroupwfPeer::GRP_STATUS . "='ACTIVE'" - . " ) AND " - . " " . AppAssignSelfServiceValueGroupPeer::ASSIGNEE_TYPE . "=2 " - . ")"; + . AppAssignSelfServiceValueGroupPeer::ASSIGNEE_ID . " IN (" . implode(",", $arrayId) . ") AND " + . " " . AppAssignSelfServiceValueGroupPeer::ASSIGNEE_TYPE . " = 2 " + . ")"; $criteria->setDistinct(); $criteria->addSelectColumn(AppAssignSelfServiceValuePeer::APP_UID); diff --git a/workflow/engine/classes/model/LoginLog.php b/workflow/engine/classes/model/LoginLog.php index c8bc914ca..568dd5bf6 100644 --- a/workflow/engine/classes/model/LoginLog.php +++ b/workflow/engine/classes/model/LoginLog.php @@ -130,5 +130,43 @@ class LoginLog extends BaseLoginLog } return $aRows; } + + /** + * Returns the last session id of a user + * @param string $userUid User uid + * @return array All session id of php + * @throws PropelException + * @throws SQLException + */ + public function getSessionsIdByUser($userUid) + { + $criteria = new Criteria(); + $criteria->addSelectColumn('LOG_SID'); + $criteria->add(LoginLogPeer::USR_UID, $userUid); + $criteria->add(LoginLogPeer::LOG_STATUS, 'ACTIVE'); + $criteria->setDistinct(); + $criteria->addDescendingOrderByColumn(LoginLogPeer::LOG_INIT_DATE); + $resultSet = LoginLogPeer::doSelectRS($criteria); + $resultSet->setFetchmode(ResultSet::FETCHMODE_ASSOC); + $row = []; + while($resultSet->next()) { + $row[] = $resultSet->getRow(); + } + return $row; + } + + /** + * Delete all records related to a user uid + * @param string $userUid User uid + * @return int + * @throws PropelException + */ + public function removeByUser($userUid) + { + $criteria = new Criteria(); + $criteria->add(LoginLogPeer::USR_UID, $userUid); + $resultSet = LoginLogPeer::doDelete($criteria); + return $resultSet; + } } diff --git a/workflow/engine/classes/model/OauthAccessTokens.php b/workflow/engine/classes/model/OauthAccessTokens.php index 6d251b992..e40db5772 100644 --- a/workflow/engine/classes/model/OauthAccessTokens.php +++ b/workflow/engine/classes/model/OauthAccessTokens.php @@ -173,6 +173,20 @@ class OauthAccessTokens extends BaseOauthAccessTokens return array("numRecTotal" => $numRecTotal, "data" => $arrayData); } + + /** + * Delete all records related to a user uid + * @param string $userUid User uid + * @return int + * @throws PropelException + */ + public function removeByUser($userUid) + { + $criteria = new Criteria(); + $criteria->add(OauthAccessTokensPeer::USER_ID, $userUid); + $resultSet = OauthAccessTokensPeer::doDelete($criteria); + return $resultSet; + } } // OauthAccessTokens diff --git a/workflow/engine/classes/model/OauthAuthorizationCodes.php b/workflow/engine/classes/model/OauthAuthorizationCodes.php index 491e49d0c..415f3229e 100644 --- a/workflow/engine/classes/model/OauthAuthorizationCodes.php +++ b/workflow/engine/classes/model/OauthAuthorizationCodes.php @@ -14,6 +14,19 @@ require_once 'classes/model/om/BaseOauthAuthorizationCodes.php'; * * @package classes.model */ -class OauthAuthorizationCodes extends BaseOauthAuthorizationCodes { - +class OauthAuthorizationCodes extends BaseOauthAuthorizationCodes +{ + /** + * Delete all records related to a user uid + * @param string $userUid User uid + * @return int + * @throws PropelException + */ + public function removeByUser($userUid) + { + $criteria = new Criteria(); + $criteria->add(OauthAuthorizationCodesPeer::USER_ID, $userUid); + $resultSet = OauthAuthorizationCodesPeer::doDelete($criteria); + return $resultSet; + } } // OauthAuthorizationCodes diff --git a/workflow/engine/classes/model/OauthClients.php b/workflow/engine/classes/model/OauthClients.php index c0fc4e9ef..8e4d2ce69 100644 --- a/workflow/engine/classes/model/OauthClients.php +++ b/workflow/engine/classes/model/OauthClients.php @@ -209,6 +209,19 @@ class OauthClients extends BaseOauthClients return array("numRecTotal" => $numRecTotal, "data" => $arrayData); } + /** + * Delete all records related to a user uid + * @param string $userUid User uid + * @return int + * @throws PropelException + */ + public function removeByUser($userUid) + { + $criteria = new Criteria(); + $criteria->add(OauthClientsPeer::USR_UID, $userUid); + $resultSet = OauthClientsPeer::doDelete($criteria); + return $resultSet; + } } // OauthClients diff --git a/workflow/engine/classes/model/OauthRefreshTokens.php b/workflow/engine/classes/model/OauthRefreshTokens.php index 5d65629be..70c4eb368 100644 --- a/workflow/engine/classes/model/OauthRefreshTokens.php +++ b/workflow/engine/classes/model/OauthRefreshTokens.php @@ -14,6 +14,19 @@ require_once 'classes/model/om/BaseOauthRefreshTokens.php'; * * @package classes.model */ -class OauthRefreshTokens extends BaseOauthRefreshTokens { - +class OauthRefreshTokens extends BaseOauthRefreshTokens +{ + /** + * Delete all records related to a user uid + * @param string $userUid User uid + * @return int + * @throws PropelException + */ + public function removeByUser($userUid) + { + $criteria = new Criteria(); + $criteria->add(OauthRefreshTokensPeer::USER_ID, $userUid); + $resultSet = OauthRefreshTokensPeer::doDelete($criteria); + return $resultSet; + } } // OauthRefreshTokens diff --git a/workflow/engine/classes/model/OutputDocument.php b/workflow/engine/classes/model/OutputDocument.php index 37da4fbf9..3d8f393e4 100644 --- a/workflow/engine/classes/model/OutputDocument.php +++ b/workflow/engine/classes/model/OutputDocument.php @@ -508,20 +508,29 @@ class OutputDocument extends BaseOutputDocument } } - /* + /** * Generate the output document - * @param string $sUID - * @param array $aFields - * @param string $sPath - * @return variant + * + * @param string $outDocUid + * @param array $caseFields + * @param string $path + * @param string $filename + * @param string $content + * @param bool $landscape + * @param string $typeDocsToGen + * @param array $properties + * + * @return mixed + * + * @see workflow/engine/methods/cases/cases_Step.php + * @see workflow/engine/classes/class.pmFunctions.php:PMFGenerateOutputDocument() */ - - public function generate($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape = false, $sTypeDocToGener = 'BOTH', $aProperties = array()) + public function generate($outDocUid, $caseFields, $path, $filename, $content, $landscape = false, $typeDocsToGen = 'BOTH', $properties = []) { - if (($sUID != '') && is_array($aFields) && ($sPath != '')) { - $sContent = G::replaceDataGridField($sContent, $aFields); + if (($outDocUid != '') && is_array($caseFields) && ($path != '')) { + $content = G::replaceDataGridField($content, $caseFields, true, true); - if (strpos($sContent, ''; - $oFile = fopen($sPath . $sFilename . '_smarty.html', 'wb'); - fwrite($oFile, $sContent); - fclose($oFile); - $template->templateFile = $sPath . $sFilename . '_smarty.html'; + $fp = fopen($path . $filename . '_smarty.html', 'wb'); + fwrite($fp, $content); + fclose($fp); + $template->templateFile = $path . $filename . '_smarty.html'; //assign the variables and use the template $template - $template->assign($aFields); - $sContent = $template->fetch($template->templateFile); + $template->assign($caseFields); + $content = $template->fetch($template->templateFile); unlink($template->templateFile); } - G::verifyPath($sPath, true); + G::verifyPath($path, true); //Start - Create .doc - $oFile = fopen($sPath . $sFilename . '.doc', 'wb'); + $fp = fopen($path . $filename . '.doc', 'wb'); $size = []; $size["Letter"] = "216mm 279mm"; @@ -566,6 +575,7 @@ class OutputDocument extends BaseOutputDocument $size["Screenshot800"] = "800mm 600mm"; $size["Screenshot1024"] = "1024mm 768mm"; + $sizeLandscape = []; $sizeLandscape["Letter"] = "279mm 216mm"; $sizeLandscape["Legal"] = "357mm 216mm"; $sizeLandscape["Executive"] = "267mm 184mm"; @@ -587,41 +597,41 @@ class OutputDocument extends BaseOutputDocument $sizeLandscape["Screenshot800"] = "600mm 800mm"; $sizeLandscape["Screenshot1024"] = "768mm 1024mm"; - if (!isset($aProperties['media'])) { - $aProperties['media'] = 'Letter'; + if (!isset($properties['media'])) { + $properties['media'] = 'Letter'; } - if ($sLandscape) { - $media = $sizeLandscape[$aProperties['media']]; + if ($landscape) { + $media = $sizeLandscape[$properties['media']]; } else { - $media = $size[$aProperties['media']]; + $media = $size[$properties['media']]; } $marginLeft = '15'; - if (isset($aProperties['margins']['left'])) { - $marginLeft = $aProperties['margins']['left']; + if (isset($properties['margins']['left'])) { + $marginLeft = $properties['margins']['left']; } $marginRight = '15'; - if (isset($aProperties['margins']['right'])) { - $marginRight = $aProperties['margins']['right']; + if (isset($properties['margins']['right'])) { + $marginRight = $properties['margins']['right']; } $marginTop = '15'; - if (isset($aProperties['margins']['top'])) { - $marginTop = $aProperties['margins']['top']; + if (isset($properties['margins']['top'])) { + $marginTop = $properties['margins']['top']; } $marginBottom = '15'; - if (isset($aProperties['margins']['bottom'])) { - $marginBottom = $aProperties['margins']['bottom']; + if (isset($properties['margins']['bottom'])) { + $marginBottom = $properties['margins']['bottom']; } - fwrite($oFile, ' @@ -667,31 +677,31 @@ class OutputDocument extends BaseOutputDocument
'); - fwrite($oFile, $sContent); - fwrite($oFile, "\n
\n\n"); - fclose($oFile); + fwrite($fp, $content); + fwrite($fp, "\n
\n\n"); + fclose($fp); /* End - Create .doc */ - if ($sTypeDocToGener == 'BOTH' || $sTypeDocToGener == 'PDF') { - $oFile = fopen($sPath . $sFilename . '.html', 'wb'); - fwrite($oFile, $sContent); - fclose($oFile); + if ($typeDocsToGen == 'BOTH' || $typeDocsToGen == 'PDF') { + $fp = fopen($path . $filename . '.html', 'wb'); + fwrite($fp, $content); + fclose($fp); /* Start - Create .pdf */ - if (isset($aProperties['report_generator'])) { - switch ($aProperties['report_generator']) { + if (isset($properties['report_generator'])) { + switch ($properties['report_generator']) { case 'TCPDF': - $this->generateTcpdf($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape, $aProperties); + $this->generateTcpdf($outDocUid, $caseFields, $path, $filename, $content, $landscape, $properties); break; case 'HTML2PDF': default: - $this->generateHtml2ps_pdf($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape, $aProperties); + $this->generateHtml2ps_pdf($outDocUid, $caseFields, $path, $filename, $content, $landscape, $properties); break; } } else { - $this->generateHtml2ps_pdf($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape, $aProperties); + $this->generateHtml2ps_pdf($outDocUid, $caseFields, $path, $filename, $content, $landscape, $properties); } } - //end if $sTypeDocToGener + //end if $typeDocsToGen /* End - Create .pdf */ } else { return PEAR::raiseError( diff --git a/workflow/engine/classes/model/PmoauthUserAccessTokens.php b/workflow/engine/classes/model/PmoauthUserAccessTokens.php index df28c54e2..e3327b597 100644 --- a/workflow/engine/classes/model/PmoauthUserAccessTokens.php +++ b/workflow/engine/classes/model/PmoauthUserAccessTokens.php @@ -29,4 +29,20 @@ class PmoauthUserAccessTokens extends BasePmoauthUserAccessTokens return (is_array($result) && empty($result)) ? false : $result[0]; } + + /** + * Delete all records related to a user uid + * + * @param string $userUid User uid + * + * @return int + */ + public function removeByUser($userUid) + { + $criteria = new Criteria(); + $criteria->add(PmoauthUserAccessTokensPeer::USER_ID, $userUid); + $resultSet = PmoauthUserAccessTokensPeer::doDelete($criteria); + + return $resultSet; + } } // PmoauthUserAccessTokens diff --git a/workflow/engine/classes/model/Process.php b/workflow/engine/classes/model/Process.php index 7e895d69d..69c59feec 100644 --- a/workflow/engine/classes/model/Process.php +++ b/workflow/engine/classes/model/Process.php @@ -775,11 +775,22 @@ class Process extends BaseProcess return $aProc; } + /** + * Get the trigger configured in committing an action in cases + * + * @param string $proUid + * @param string $action + * + * @return mixed + * + * @see Cases::getExecuteTriggerProcess() + * @link https://wiki.processmaker.com/3.2/Triggers#When_action_cases + */ public function getTriggerWebBotProcess($proUid, $action) { require_once("classes/model/Triggers.php"); - if ((! isset($proUid) && $proUid == '') || (! isset($action) && $action == '')) { + if (empty($proUid) || empty($action)){ return false; } @@ -788,40 +799,41 @@ class Process extends BaseProcess switch ($action) { case 'CREATE': - $var = ProcessPeer::PRO_TRI_CREATE; + $columnName = ProcessPeer::PRO_TRI_CREATE; break; case 'OPEN': - $var = ProcessPeer::PRO_TRI_OPEN; + $columnName = ProcessPeer::PRO_TRI_OPEN; break; case 'DELETED': - $var = ProcessPeer::PRO_TRI_DELETED; + $columnName = ProcessPeer::PRO_TRI_DELETED; break; case 'CANCELED': - $var = ProcessPeer::PRO_TRI_CANCELED; + $columnName = ProcessPeer::PRO_TRI_CANCELED; break; case 'PAUSED': - $var = ProcessPeer::PRO_TRI_PAUSED; + $columnName = ProcessPeer::PRO_TRI_PAUSED; break; case 'REASSIGNED': - $var = ProcessPeer::PRO_TRI_REASSIGNED; + $columnName = ProcessPeer::PRO_TRI_REASSIGNED; break; case "UNPAUSE": - $var = ProcessPeer::PRO_TRI_UNPAUSED; + $columnName = ProcessPeer::PRO_TRI_UNPAUSED; break; } - $oCriteria = new Criteria('workflow'); - $oCriteria->addSelectColumn($var); - $oCriteria->addSelectColumn(TriggersPeer::TRI_UID); - $oCriteria->addSelectColumn(TriggersPeer::TRI_WEBBOT); - $oCriteria->addJoin($var, TriggersPeer::TRI_UID, Criteria::LEFT_JOIN); - $oCriteria->add(ProcessPeer::PRO_UID, $proUid); - $oDataSet = ProcessPeer::doSelectRS($oCriteria, Propel::getDbConnection('workflow_ro')); + $criteria = new Criteria('workflow'); + $criteria->addSelectColumn($columnName); + $criteria->addSelectColumn(TriggersPeer::TRI_UID); + $criteria->addSelectColumn(TriggersPeer::TRI_WEBBOT); + $criteria->addSelectColumn(TriggersPeer::TRI_TITLE); + $criteria->addJoin($columnName, TriggersPeer::TRI_UID, Criteria::LEFT_JOIN); + $criteria->add(ProcessPeer::PRO_UID, $proUid); + $criteria->add($columnName, '', Criteria::NOT_EQUAL); + $dataSet = ProcessPeer::doSelectRS($criteria, Propel::getDbConnection('workflow_ro')); + $dataSet->setFetchmode(ResultSet::FETCHMODE_ASSOC); - $oDataSet->setFetchmode(ResultSet::FETCHMODE_ASSOC); - if ($oDataSet->next()) { - $row = $oDataSet->getRow(); - $arrayWebBotTrigger = ['TRI_UID' => $row['TRI_UID'], 'TRI_WEBBOT' => $row['TRI_WEBBOT']]; + if ($dataSet->next()) { + $arrayWebBotTrigger[] = $dataSet->getRow(); } //Return diff --git a/workflow/engine/classes/model/Session.php b/workflow/engine/classes/model/Session.php index 918a47fb8..fa682223a 100644 --- a/workflow/engine/classes/model/Session.php +++ b/workflow/engine/classes/model/Session.php @@ -20,5 +20,18 @@ require_once 'classes/model/om/BaseSession.php'; */ class Session extends BaseSession { + /** + * Delete all records related to a user uid + * @param string $userUid User uid + * @return int + * @throws PropelException + */ + public function removeByUser($userUid) + { + $criteria = new Criteria(); + $criteria->add(SessionPeer::USR_UID, $userUid); + $resultSet = SessionPeer::doDelete($criteria); + return $resultSet; + } } diff --git a/workflow/engine/classes/model/SubApplication.php b/workflow/engine/classes/model/SubApplication.php index 59466a920..175f69e6c 100644 --- a/workflow/engine/classes/model/SubApplication.php +++ b/workflow/engine/classes/model/SubApplication.php @@ -152,5 +152,29 @@ class SubApplication extends BaseSubApplication return $result; } + + + /** + * Load all cases with the same parent case + * + * @param $appUid + * + * @return array + */ + public function loadByAppUidParent($appUid) + { + $criteria = new Criteria('workflow'); + $criteria->add(SubApplicationPeer::APP_PARENT, $appUid); + $dataSet = SubApplicationPeer::doSelectRS($criteria); + + $dataSet->setFetchmode(ResultSet::FETCHMODE_ASSOC); + + $result = []; + while ($dataSet->next()) { + $result[] = $dataSet->getRow(); + } + + return $result; + } } diff --git a/workflow/engine/config/mobile.ini b/workflow/engine/config/mobile.ini index b76af1aa3..26feba970 100644 --- a/workflow/engine/config/mobile.ini +++ b/workflow/engine/config/mobile.ini @@ -1,6 +1,6 @@ ;Setting Android -android[url] = "https://android.googleapis.com/gcm/send" -android[serverApiKey] = "AIzaSyALwyLUYtZDcJQr54V5rxhZjoWnOLWCSvc" +android[url] = "https://fcm.googleapis.com/fcm/send" +android[serverApiKey] = "AAAAMvip2iU:APA91bHFAvHmCsSh0zbRaC9Xo2EPIbbRYzehkFAKUdXmj_ZVBOOO52npae183LYUONHjNPHaKo1MqT4BWiEuTF7HVEMfwn05XOA-h1LQ_bJ0ezAA35l-wADPq5VtKDiHT1VFGW1oeU7L" ;Setting Apple apple[url] = "ssl://gateway.push.apple.com:2195" diff --git a/workflow/engine/config/mobileios.pem b/workflow/engine/config/mobileios.pem index bb56d7bda..6a0728eef 100644 --- a/workflow/engine/config/mobileios.pem +++ b/workflow/engine/config/mobileios.pem @@ -1,111 +1,73 @@ ------BEGIN CERTIFICATE----- -MIIGVTCCBT2gAwIBAgIIC2XzArbAqykwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV -BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js -ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3 -aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw -HhcNMTcxMDA0MTM0MzMwWhcNMTgxMTAzMTM0MzMwWjCBqTEtMCsGCgmSJomT8ixk -AQEMHWNvbS5wcm9jZXNzbWFrZXIuUHJvY2Vzc01ha2VyMTswOQYDVQQDDDJBcHBs -ZSBQdXNoIFNlcnZpY2VzOiBjb20ucHJvY2Vzc21ha2VyLlByb2Nlc3NNYWtlcjET -MBEGA1UECwwKOTQyUVA3UUpFOTEZMBcGA1UECgwQUHJvY2Vzc01ha2VyIEluYzEL -MAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDwQgZG -uKp6qEd1Uwgh0qmJLEFlMaIPjxkY+mGjbZyZys73oenLHgPwPukm+64oPdxs7UXl -ZifbWYU4rHbQDEkmOC4GyQU5n9s4zgNtgTqCpab3BuODA/1ffm2OullK1SHmS0cG -Cm8WC93SDa9nmF5xIaiUBbfOsZGcjUKM+MTn/5ETWoZEBUqlf5PKPGZ63/99Q/pj -UxNftY3LTE3o37GYATxFX/sIFtB98vB5hcTdt4zfXHzwisAtqQpkuWIGd5nULX5w -JzlAUjq4werqQhg/k/OAw7kL/JP/PDHpgrbCoO9BZTsAD8H21aZDZR1uDSFSa4H/ -2FeWj286U6Uu10XfAgMBAAGjggKQMIICjDAdBgNVHQ4EFgQUZtV15ABNLGW8Kjjp -yUaQl6f5eRowDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBSIJxcJqbYYYIvs67r2 -R1nFUlSjtzCCARwGA1UdIASCARMwggEPMIIBCwYJKoZIhvdjZAUBMIH9MIHDBggr -BgEFBQcCAjCBtgyBs1JlbGlhbmNlIG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55 -IHBhcnR5IGFzc3VtZXMgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxl -IHN0YW5kYXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNh -dGUgcG9saWN5IGFuZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMu -MDUGCCsGAQUFBwIBFilodHRwOi8vd3d3LmFwcGxlLmNvbS9jZXJ0aWZpY2F0ZWF1 -dGhvcml0eTAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vY3JsLmFwcGxlLmNvbS93 -d2RyY2EuY3JsMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAjAQ -BgoqhkiG92NkBgMBBAIFADAQBgoqhkiG92NkBgMCBAIFADCBoAYKKoZIhvdjZAYD -BgSBkTCBjgwdY29tLnByb2Nlc3NtYWtlci5Qcm9jZXNzTWFrZXIwBQwDYXBwDCJj -b20ucHJvY2Vzc21ha2VyLlByb2Nlc3NNYWtlci52b2lwMAYMBHZvaXAMKmNvbS5w -cm9jZXNzbWFrZXIuUHJvY2Vzc01ha2VyLmNvbXBsaWNhdGlvbjAODAxjb21wbGlj -YXRpb24wDQYJKoZIhvcNAQELBQADggEBADLO70r/cMu7M2A1xNu356IBL4vOtGK7 -nKaAxnjt7aZB+qGTz9xzjH0sHKIefAtlTTSzUzcR/9+gprKt4cdmwgV0zWBpO0UU -7Nu0WreMJKKJ1COO26d8WywvaNdWWHH7+lksZBJFiqFcYvECu3CaMoe77PUqKrWy -R/7MhsHtTsMLz/IMATgMU32NTUs3qKElXjHwTOyE2c+n5VYNoDDMUpx//mbZ5K1B -zA12bA2lg5VLXq4yA9p2Xc2JBg647CXcMQdzPphQ/NZaetcfmE0F01FAF3dfhmmX -jbNoPanngYpPEUVR6kt4MpB/3SeBXgU3HPhBIo7vtfIwI0wT+QlB5bw= ------END CERTIFICATE----- Bag Attributes friendlyName: Apple Push Services: com.processmaker.ProcessMaker - localKeyID: 66 D5 75 E4 00 4D 2C 65 BC 2A 38 E9 C9 46 90 97 A7 F9 79 1A + localKeyID: F1 9A 92 AC CD 22 C3 0B 7A 24 A2 EE 2F 93 87 DD 0E 97 F3 FA subject=/UID=com.processmaker.ProcessMaker/CN=Apple Push Services: com.processmaker.ProcessMaker/OU=942QP7QJE9/O=ProcessMaker Inc/C=US issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority -----BEGIN CERTIFICATE----- -MIIGVTCCBT2gAwIBAgIIC2XzArbAqykwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV +MIIGVTCCBT2gAwIBAgIIBHXDf7O3LYgwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3 aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw -HhcNMTcxMDA0MTM0MzMwWhcNMTgxMTAzMTM0MzMwWjCBqTEtMCsGCgmSJomT8ixk +HhcNMTgxMjE4MTcyMzUxWhcNMjAwMTE3MTcyMzUxWjCBqTEtMCsGCgmSJomT8ixk AQEMHWNvbS5wcm9jZXNzbWFrZXIuUHJvY2Vzc01ha2VyMTswOQYDVQQDDDJBcHBs ZSBQdXNoIFNlcnZpY2VzOiBjb20ucHJvY2Vzc21ha2VyLlByb2Nlc3NNYWtlcjET MBEGA1UECwwKOTQyUVA3UUpFOTEZMBcGA1UECgwQUHJvY2Vzc01ha2VyIEluYzEL -MAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDwQgZG -uKp6qEd1Uwgh0qmJLEFlMaIPjxkY+mGjbZyZys73oenLHgPwPukm+64oPdxs7UXl -ZifbWYU4rHbQDEkmOC4GyQU5n9s4zgNtgTqCpab3BuODA/1ffm2OullK1SHmS0cG -Cm8WC93SDa9nmF5xIaiUBbfOsZGcjUKM+MTn/5ETWoZEBUqlf5PKPGZ63/99Q/pj -UxNftY3LTE3o37GYATxFX/sIFtB98vB5hcTdt4zfXHzwisAtqQpkuWIGd5nULX5w -JzlAUjq4werqQhg/k/OAw7kL/JP/PDHpgrbCoO9BZTsAD8H21aZDZR1uDSFSa4H/ -2FeWj286U6Uu10XfAgMBAAGjggKQMIICjDAdBgNVHQ4EFgQUZtV15ABNLGW8Kjjp -yUaQl6f5eRowDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBSIJxcJqbYYYIvs67r2 -R1nFUlSjtzCCARwGA1UdIASCARMwggEPMIIBCwYJKoZIhvdjZAUBMIH9MIHDBggr -BgEFBQcCAjCBtgyBs1JlbGlhbmNlIG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55 -IHBhcnR5IGFzc3VtZXMgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxl -IHN0YW5kYXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNh -dGUgcG9saWN5IGFuZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMu -MDUGCCsGAQUFBwIBFilodHRwOi8vd3d3LmFwcGxlLmNvbS9jZXJ0aWZpY2F0ZWF1 -dGhvcml0eTAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vY3JsLmFwcGxlLmNvbS93 -d2RyY2EuY3JsMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAjAQ +MAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTiJTM +ExiPxHCgYAD5MUlKnx0z8lQfk0///r12hi36bbXeGWceaCyGMEgWgryAmkvyCTde +gMqE8h9mlEMnq11vwPu9KRjJufnIeGZjpz5JdF5kD+XQp9S5epYgBodJyuLQsFi+ +1d9sArsgNx0xZX+B2qh+Q+GO8/r+01JxwSmecSG5SQQgZZzeCp6soGIKMtxkt4Rp +WCAkV0pROnLF18EVwlHGaFCwABoTR8q5mkixaekyWeRfyb6WoOVXAA/l9fbxTXKr +/4yRV6Gw7Jtu5vmULSqVlfXWTbhNf27hE/sYQmdW124j6uT6UvYF+DPen1PwOore +TaKxqjHbpNvPc6OJAgMBAAGjggKQMIICjDAMBgNVHRMBAf8EAjAAMB8GA1UdIwQY +MBaAFIgnFwmpthhgi+zruvZHWcVSVKO3MIIBHAYDVR0gBIIBEzCCAQ8wggELBgkq +hkiG92NkBQEwgf0wgcMGCCsGAQUFBwICMIG2DIGzUmVsaWFuY2Ugb24gdGhpcyBj +ZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2NlcHRhbmNlIG9mIHRo +ZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlvbnMg +b2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2Ugc3RhdGVtZW50cy4wNQYIKwYBBQUHAgEWKWh0dHA6Ly93d3cuYXBwbGUu +Y29tL2NlcnRpZmljYXRlYXV0aG9yaXR5MBMGA1UdJQQMMAoGCCsGAQUFBwMCMDAG +A1UdHwQpMCcwJaAjoCGGH2h0dHA6Ly9jcmwuYXBwbGUuY29tL3d3ZHJjYS5jcmww +HQYDVR0OBBYEFPGakqzNIsMLeiSi7i+Th90Ol/P6MA4GA1UdDwEB/wQEAwIHgDAQ BgoqhkiG92NkBgMBBAIFADAQBgoqhkiG92NkBgMCBAIFADCBoAYKKoZIhvdjZAYD BgSBkTCBjgwdY29tLnByb2Nlc3NtYWtlci5Qcm9jZXNzTWFrZXIwBQwDYXBwDCJj b20ucHJvY2Vzc21ha2VyLlByb2Nlc3NNYWtlci52b2lwMAYMBHZvaXAMKmNvbS5w cm9jZXNzbWFrZXIuUHJvY2Vzc01ha2VyLmNvbXBsaWNhdGlvbjAODAxjb21wbGlj -YXRpb24wDQYJKoZIhvcNAQELBQADggEBADLO70r/cMu7M2A1xNu356IBL4vOtGK7 -nKaAxnjt7aZB+qGTz9xzjH0sHKIefAtlTTSzUzcR/9+gprKt4cdmwgV0zWBpO0UU -7Nu0WreMJKKJ1COO26d8WywvaNdWWHH7+lksZBJFiqFcYvECu3CaMoe77PUqKrWy -R/7MhsHtTsMLz/IMATgMU32NTUs3qKElXjHwTOyE2c+n5VYNoDDMUpx//mbZ5K1B -zA12bA2lg5VLXq4yA9p2Xc2JBg647CXcMQdzPphQ/NZaetcfmE0F01FAF3dfhmmX -jbNoPanngYpPEUVR6kt4MpB/3SeBXgU3HPhBIo7vtfIwI0wT+QlB5bw= +YXRpb24wDQYJKoZIhvcNAQELBQADggEBAHeOD1oHNW5cRUSq52dIpzBxp/9QnK4M +v9YeNempdjI9ajo3gHzA2iJHpy5+JWTkxuE7iUdTP4KfjL/vYPIJvCdESv+o7wre +SfLMlarSx5X+AmCDsQLMVyb3aoiNA4qE16OIpu+UTs7Np90xtL4bsgLLf0wwVLSF +x74NKKEQLgrhjfThnmZ8a4u7CiVhXSGPosqaXyT43WXKyWreDnCW1Pzm+sfSlD43 +yCKglvGJeDvfWb1RfEJpqNWp7duAb/HiD2oIWrdtN+6XYEucQEuRrKfj2XOHS1+r +rmsU8hWBHhGgMYectSe4nXBOCtyOzDTaYIs+TVCt+xnxCq5ItUaxSQo= -----END CERTIFICATE----- Bag Attributes - friendlyName: ProcessMaker Prod Key - localKeyID: 66 D5 75 E4 00 4D 2C 65 BC 2A 38 E9 C9 46 90 97 A7 F9 79 1A + friendlyName: Mauricio Veliz + localKeyID: F1 9A 92 AC CD 22 C3 0B 7A 24 A2 EE 2F 93 87 DD 0E 97 F3 FA Key Attributes: ------BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,6D70077A389A3A8C - -bziMWwK5LMeP0dIM2wHeO6juXqzmtH/U9FW5GAZuJEKt0zYAyv1DmEJFfyMMZmob -4j+LfvfdZVium6cIEkC+JMPFwW0dSRQNgA6I44E2AT73MTQr6u7pZi/QiQ09CJCQ -JjFJ2Q08ZgHQXrJMy62PeHO+uWOQW6YuI5aNC/K+AdvIwNyzlCj/HNWcf7IeSaeE -urH5/dL1cVSfpeBXMsqfYSAcfTZOXgAb8BRwngi+RSGNQ6SawEl53vm94gDSH3Mi -3tzCsDcw0Gw5Wu1d/755Zzakl48LOqxLzptbOr5QbJK5BeGhE0y3Db+rYNpG3fzw -I3YdZTMhkzaigG4xp/BLyLL2tgGzSIGg8BARMHF/GkXcdKBJyQrweXMkhhoeYxr2 -dzWurOd0Bkw3DJXONE9uPNQb/i33TYmflQMhWJFlHkKhkHlIgAu5cIzTwRNbHCF7 -aRKiHz5uL+/WufgVlw62JZp9JZ1mPsmJINba4BAT9i9zkUnPvxYN/GB5Z2Ttz1nj -ylyGiAtdAZ7l05OWd7I9gEUTce8dsojThIun3QQ1UFCRJUmg38Dp/XxMzWP5IpTb -E2McM90jyN+M8gII2KU6U5uqTXDiMMFiXFa9WlTc4xIkHNQLINDASBgUQr7pIqth -UTvU4YoST6wma9BNYAuGX9ga6uEg94kmVXrUEBZWI13T56bSpw4cyvzSJvNwcH8m -nClVXMIrysoGgQ1Gxs6G2xWTduXysK5E26bY6Gypk9VPMUyo6oVENnY3EQs3Cj/R -W2vyz1t05xPonPxmun2mFTQQvgSbbkfUbuL02tBQXxkWNoo5rCAVuRMFlVjFzIEF -qZ3uiU8ui5Nj1Tc5SAosuoTu53vLp4ynn9A5WVmLXdE1DucCXTumN8teISF69cUU -XYVy2Ch39LxUGumWTSVZNDJBJgSFtiNxCmpwS4jQsNRF9piK/T+t3INSXRcRB9mF -f3DYOrjor6TTu0hEppZosIUfoo7EDgplfMK5x9ZjL8JWSWEqA2U2JoRbe9ucMkGy -wbFTsbyg9NNSdF1jEZUEKWKr7dT3ShPHhut/F9HOi5KvbMAgUf0HnYgUsCTYhZru -UbVf8cWnfYPyVUW3Doa12/uSpqwrHzOduexb1LzO0mukdfyR7UhY/rRv5w4KkTXJ -+zlNncWiSZQiDJq053i8UYhDj0U7+YzmpxE/BUU5HwMcZ8wtl0MDac66Z1YXkqgs -bO2dK71tNQ1D5msmDDP+Cw0W4wLdRiJn8FNF5oBl2QYMyTyclduhrlCMp8VgnMmT -mDrygATrWoaToSiR+Mc6D7rOLyHt+29HMtFx1Lgs3jpgzLQ4nBWBtLN5uxkxTclH -W35sMR2eDYiM7nEO9TJSBlC8lkFiGsv4xYYK8gLEZ2h7OMPrO/9L9CmHk/v3Ts8I -wSt0FiVZNP4JEL0NZ5nSZMnDT0R47CuFkEgf271Um4lNPPRV7mPA0fWkKXt59FeK -LoBZYkGes/QliAUWdY44tVKgg6oIM6IqubsO92Hru5o36Px7ucVoqiNHnSy1lo/v -KAfvW9/40XJ+z1JUTYwreaLoO+Wlk0Irkvv4Fro0KTA8rXDNFm/JL2gkgknEae4i ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDTiJTMExiPxHCg +YAD5MUlKnx0z8lQfk0///r12hi36bbXeGWceaCyGMEgWgryAmkvyCTdegMqE8h9m +lEMnq11vwPu9KRjJufnIeGZjpz5JdF5kD+XQp9S5epYgBodJyuLQsFi+1d9sArsg +Nx0xZX+B2qh+Q+GO8/r+01JxwSmecSG5SQQgZZzeCp6soGIKMtxkt4RpWCAkV0pR +OnLF18EVwlHGaFCwABoTR8q5mkixaekyWeRfyb6WoOVXAA/l9fbxTXKr/4yRV6Gw +7Jtu5vmULSqVlfXWTbhNf27hE/sYQmdW124j6uT6UvYF+DPen1PwOoreTaKxqjHb +pNvPc6OJAgMBAAECggEAfYWZjjNyqrUNhA0T5sr5S795S77rbkUy/pxB/xgGJol9 +lwqJ50A303TJAhqYEtP8ZuZTJc/U3Ojz+yHVa6/DZTIl74x4ehPShcP0NgQi8OGN +tWC9pYBBucJlXSGinAY5a06JisxMpMJGGgq6Vvp8nCiNPUe4i+R5N0dcr8XIlYxG +FU+r6rGqmcRGxPp8yQfh5fP1P+9xyjZt1WuUuvF4Y5dTeVmR0z/dZQqlrC0Q5hAD +kAfimf31ViPYaNwhxHTG53aC8GMbRJqTeM/MW3bZ+dVRcW8Yk2Ym/mbDY3cQvi0V +sGOVDHaoJNa8pfQNZ+y+tvJPRYIdbmPG2pGcJeuqAQKBgQDtQiZ8/V4DBmboZyBt +60Rnafue1bSfQssxoOuNtlRosOW28piCfNRftYhCKT3ylKbPVY02ekNisUIJYaZI +8ipCGNGdZD2oOitWVYDDq+A9O28JinsJc5i9ffQQ6dK+Krw5k7Bo4DzytwhJlwXa +8YxvntN7PlzM68wncKL+1jnwSQKBgQDkPjilC/4UiXnGmhFeu6oZ6dz0V7yjdoP0 +ApdHVsOvCyIIl34vBy4Du4iZ/xXzwd+ZwOsTHXf8iU1Ayig5WFNDsr+HRItvNRg+ +FxOSiqLnclJYsJMNtGN7SnlTKyGWGpxzCydaeOq1Yapq8VkcFL9gtZYt911prD0u +THx2vRKZQQKBgF3ZwOfIQZvouGROBuH0IobVwZa+6kflYAMtqH/SE+mlr/iCVhmn +z0pcwJ2LOtnuO13gdY+LJYSwoXKcke5g/J5QuvoLYOheui3YfKrqHjWagP3BLZI7 +i7vJSvY1yAs5VGNiLHIP4YwRItIZT1OgIPE2Xmlt7b+RtpwTTiaIDzshAoGBAMmN +TJYq9e8Ky5eem/ItBHQnuW+oPrOWx8VluFNOAjWEPkSaCtramz6+j012HduIe70Z +yDy0DC3czXSGUGj7X2Pr6Ag6dmr41vSVijog5OQ/Zwpcuy8h+at5Q5Q3BUy5KSjK +U7EoEBOmMEiJ4ifTBoEPOZRT2ZCkgc5tyodMRa1BAoGAKE39g4yX+H+/kXtXqe7d +/lCBWbPTLGxo43HROjcftXvsZi+voYDlDQVfD6d3Ew8rLMWYfZ4hVYtWR4AeE0My +7aeW6JX2hD6kANFOlOCOUApZeL2X9SiCUyXQWb5M+oSmS63IWK9eHamBNqzpY6HU +V2ajfnwBPcbydtbtUcv7D7k= +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/workflow/engine/content/translations/english/processmaker.en.po b/workflow/engine/content/translations/english/processmaker.en.po index 57caa88d5..e729537fe 100644 --- a/workflow/engine/content/translations/english/processmaker.en.po +++ b/workflow/engine/content/translations/english/processmaker.en.po @@ -3863,6 +3863,12 @@ msgstr "Case Tracker Properties Saved Successfully" msgid "The case {APP_NUMBER} was reactivated successfully!" msgstr "The case {APP_NUMBER} was reactivated successfully!" +# TRANSLATION +# LABEL/ID_CASE_RESPONSE_NOT_AVAILABLE +#: LABEL/ID_CASE_RESPONSE_NOT_AVAILABLE +msgid "No response available, please review the case information" +msgstr "No response available, please review the case information" + # TRANSLATION # LABEL/ID_CASE_ROUTED_TO #: LABEL/ID_CASE_ROUTED_TO @@ -15173,6 +15179,12 @@ msgstr "Screenshot640" msgid "The input document is required, please select the value." msgstr "The input document is required, please select the value." +# TRANSLATION +# LABEL/ID_MAFE_99567b953da8beace4e3e7296bf1fc23 +#: LABEL/ID_MAFE_99567b953da8beace4e3e7296bf1fc23 +msgid "Assign type" +msgstr "Assign type" + # TRANSLATION # LABEL/ID_MAFE_99b2439e63f73ad515f7ab2447a80673 #: LABEL/ID_MAFE_99b2439e63f73ad515f7ab2447a80673 @@ -15551,6 +15563,12 @@ msgstr "Ok" msgid "Notify the assigned user to this task" msgstr "Notify the assigned user to this task" +# TRANSLATION +# LABEL/ID_MAFE_a6122a65eaa676f700ae68d393054a37 +#: LABEL/ID_MAFE_a6122a65eaa676f700ae68d393054a37 +msgid "Start" +msgstr "Start" + # TRANSLATION # LABEL/ID_MAFE_a6527af0da63377b07a3effae750a485 #: LABEL/ID_MAFE_a6527af0da63377b07a3effae750a485 @@ -16373,6 +16391,12 @@ msgstr "Invalid Connection between elements" msgid "Invalid operation: Delete message flow before converting it to" msgstr "Invalid operation: Delete message flow before converting it to" +# TRANSLATION +# LABEL/ID_MAFE_c5e54f7804fa817826dfa5ecc13cd92f +#: LABEL/ID_MAFE_c5e54f7804fa817826dfa5ecc13cd92f +msgid "Last User Name" +msgstr "Last User Name" + # TRANSLATION # LABEL/ID_MAFE_c5f93fd19468533ea5c9114801c2958d #: LABEL/ID_MAFE_c5f93fd19468533ea5c9114801c2958d @@ -17225,6 +17249,12 @@ msgstr "Select a Control" msgid "Please configure script to wait for a signal." msgstr "Please configure script to wait for a signal." +# TRANSLATION +# LABEL/ID_MAFE_e2ac1703ae8a4bb8b146f7337a7e4cab +#: LABEL/ID_MAFE_e2ac1703ae8a4bb8b146f7337a7e4cab +msgid "Last User" +msgstr "Last User" + # TRANSLATION # LABEL/ID_MAFE_e2b9d6eb9f3ec7d4e6089274a4481fab #: LABEL/ID_MAFE_e2b9d6eb9f3ec7d4e6089274a4481fab @@ -17705,6 +17735,12 @@ msgstr "Assignment" msgid "EXCLUSIVE" msgstr "EXCLUSIVE" +# TRANSLATION +# LABEL/ID_MAFE_f45fabda0c6a595f709b3996398132f5 +#: LABEL/ID_MAFE_f45fabda0c6a595f709b3996398132f5 +msgid "Diverging gateways expect to receive only one incoming flow." +msgstr "Diverging gateways expect to receive only one incoming flow." + # TRANSLATION # LABEL/ID_MAFE_f4636507ca93332f92f92fb219a43b02 #: LABEL/ID_MAFE_f4636507ca93332f92f92fb219a43b02 @@ -23123,6 +23159,36 @@ msgstr "Username" msgid "Search XML metadata" msgstr "Search XML metadata" +# TRANSLATION +# LABEL/ID_SEARCHING +#: LABEL/ID_SEARCHING +msgid "Searching..." +msgstr "Searching..." + +# TRANSLATION +# LABEL/ID_SEARCHING_CANCEL_MESSAGE +#: LABEL/ID_SEARCHING_CANCEL_MESSAGE +msgid "We are still gathering your search results. This may take a while based on your search criteria. You may cancel this search at any time" +msgstr "We are still gathering your search results. This may take a while based on your search criteria. You may cancel this search at any time" + +# TRANSLATION +# LABEL/ID_SEARCHING_TIME_OUT +#: LABEL/ID_SEARCHING_TIME_OUT +msgid "Your search timed out" +msgstr "Your search timed out" + +# TRANSLATION +# LABEL/ID_SEARCHING_UNEXPECTED_ERROR +#: LABEL/ID_SEARCHING_UNEXPECTED_ERROR +msgid "An unexpected error occurred while searching for your results. Error Code {0} and Please contact your administrator." +msgstr "An unexpected error occurred while searching for your results. Error Code {0} and Please contact your administrator." + +# TRANSLATION +# LABEL/ID_SEARCHING_UNEXPECTED_ERROR_DEFAULT +#: LABEL/ID_SEARCHING_UNEXPECTED_ERROR_DEFAULT +msgid "An unexpected error occurred while searching for your results. Please contact your administrator." +msgstr "An unexpected error occurred while searching for your results. Please contact your administrator." + # TRANSLATION # LABEL/ID_SECOND #: LABEL/ID_SECOND @@ -24851,6 +24917,18 @@ msgstr "Error: The application {0} is not canceled." msgid "The default configuration was not defined" msgstr "The default configuration was not defined" +# TRANSLATION +# LABEL/ID_THE_FILE_SIZE_IS_BIGGER_THAN_THE_MAXIMUM_ALLOWED +#: LABEL/ID_THE_FILE_SIZE_IS_BIGGER_THAN_THE_MAXIMUM_ALLOWED +msgid "The file size is bigger than the maximum allowed, the maximum size allowed is {0} Mbytes." +msgstr "The file size is bigger than the maximum allowed, the maximum size allowed is {0} Mbytes." + +# TRANSLATION +# LABEL/ID_THE_MAXIMUM_VALUE_OF_THIS_FIELD_IS +#: LABEL/ID_THE_MAXIMUM_VALUE_OF_THIS_FIELD_IS +msgid "The maximum value of this field is {0}." +msgstr "The maximum value of this field is {0}." + # TRANSLATION # LABEL/ID_THE_MIMETYPE_EXTENSION_ERROR #: LABEL/ID_THE_MIMETYPE_EXTENSION_ERROR @@ -25208,8 +25286,8 @@ msgstr "Tools" # TRANSLATION # LABEL/ID_TOO_MANY_REQUESTS #: LABEL/ID_TOO_MANY_REQUESTS -msgid "Too many requests" -msgstr "Too many requests" +msgid "Upon configurations, you have reached the maximum number of files to upload." +msgstr "Upon configurations, you have reached the maximum number of files to upload." # TRANSLATION # LABEL/ID_TOP_MARGIN diff --git a/workflow/engine/controllers/adminProxy.php b/workflow/engine/controllers/adminProxy.php index 4809054bc..65d1fafdc 100644 --- a/workflow/engine/controllers/adminProxy.php +++ b/workflow/engine/controllers/adminProxy.php @@ -574,8 +574,10 @@ class adminProxy extends HttpProxyController } /** - * for send email configuration - * @autor Alvaro + * For test email configuration + * @return stdClass() + * + * @see adminProxy->testConnection() */ public function sendTestMail() { @@ -624,7 +626,7 @@ class adminProxy extends HttpProxyController '', '', '', - 'TEST', + WsBase::MESSAGE_TYPE_TEST_EMAIL, $subject, $from, $_POST['TO'], @@ -1026,7 +1028,7 @@ class adminProxy extends HttpProxyController */ public function uploadImage() { - ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) { + ValidationUploadedFiles::getValidationUploadedFiles()->dispatch(function($validator) { echo G::json_encode([ 'success' => true, 'failed' => true, diff --git a/workflow/engine/controllers/appProxy.php b/workflow/engine/controllers/appProxy.php index b54ca5502..3d9f519f4 100644 --- a/workflow/engine/controllers/appProxy.php +++ b/workflow/engine/controllers/appProxy.php @@ -1,4 +1,6 @@ message = G::LoadTranslation('ID_LOGIN_AGAIN'); @@ -23,15 +25,22 @@ class AppProxy extends HttpProxyController * @param int $httpData->start * @param int $httpData->limit * @param string $httpData->appUid (optionalif it is not passed try use $_SESSION['APPLICATION']) - * @return array containg the case notes + * @return array containing the case notes + * + * @see workflow/engine/methods/cases/open.php + * @see workflow/engine/methods/cases/casesListExtJs.php + * @see workflow/engine/methods/cases/casesConsolidatedListExtJs.php + * + * @link https://wiki.processmaker.com/3.2/Case_Notes + * @link https://wiki.processmaker.com/3.2/Cases/Case_Notes */ - function getNotesList ($httpData) + function getNotesList($httpData) { if (!isset($_SESSION['USER_LOGGED'])) { $response = new stdclass(); $response->message = G::LoadTranslation('ID_LOGIN_AGAIN'); $response->lostSession = true; - print G::json_encode( $response ); + print G::json_encode($response); die(); } @@ -66,8 +75,7 @@ class AppProxy extends HttpProxyController $httpData->pro = $caseLoad['PRO_UID']; } - if(!isset($httpData->pro) || empty($httpData->pro) ) - { + if (!isset($httpData->pro) || empty($httpData->pro)) { $proUid = $_SESSION['PROCESS']; } else { $proUid = $httpData->pro; @@ -80,12 +88,15 @@ class AppProxy extends HttpProxyController } $usrUid = $_SESSION['USER_LOGGED']; - $respView = $case->getAllObjectsFrom($proUid, $appUid, $tasUid, $usrUid, "VIEW", $delIndex); + $respView = $case->getAllObjectsFrom($proUid, $appUid, $tasUid, $usrUid, "VIEW", $delIndex); $respBlock = $case->getAllObjectsFrom($proUid, $appUid, $tasUid, $usrUid, "BLOCK", $delIndex); if ($respView['CASES_NOTES'] == 0 && $respBlock['CASES_NOTES'] == 0) { - return array ('totalCount' => 0,'notes' => array (),'noPerms' => 1 - ); + return [ + 'totalCount' => 0, + 'notes' => [], + 'noPerms' => 1 + ]; } $usrUid = isset($_SESSION['USER_LOGGED']) ? $_SESSION['USER_LOGGED'] : ""; @@ -93,6 +104,12 @@ class AppProxy extends HttpProxyController $response = $appNotes->getNotesList($appUid, '', $httpData->start, $httpData->limit); $response = AppNotes::applyHtmlentitiesInNotes($response); + $iterator = 0; + foreach ($response['array']['notes'] as $value) { + $response ['array']['notes'][$iterator]['NOTE_DATE'] = DateTime::convertUtcToTimeZone($value['NOTE_DATE']); + $iterator++; + } + require_once("classes/model/Application.php"); $oApplication = new Application(); $aApplication = $oApplication->Load($appUid); diff --git a/workflow/engine/controllers/designer.php b/workflow/engine/controllers/designer.php index ed889372e..ee76774c3 100644 --- a/workflow/engine/controllers/designer.php +++ b/workflow/engine/controllers/designer.php @@ -11,9 +11,10 @@ use ProcessMaker\Plugins\PluginRegistry; */ use Maveriks\Util\ClassLoader; -use \OAuth2\Request; -use \ProcessMaker\BusinessModel\Light\Tracker; -use \ProcessMaker\Services\OAuth2\Server; +use OAuth2\Request; +use ProcessMaker\BusinessModel\InputDocument; +use ProcessMaker\BusinessModel\Light\Tracker; +use ProcessMaker\Services\OAuth2\Server; class Designer extends Controller { @@ -27,6 +28,8 @@ class Designer extends Controller * Index Action * * @param string $httpData (opional) + * + * @see Controller->call() */ public function index($httpData) { @@ -70,6 +73,8 @@ class Designer extends Controller $this->setVar("SYS_SKIN", SYS_SKIN); $this->setVar('HTTP_SERVER_HOSTNAME', System::getHttpServerHostnameRequestsFrontEnd()); $this->setVar('PMDYNAFORM_FIRST_TIME', $userProperties->getPmdynaformFirstTime()); + $inpuDocument = new InputDocument(); + $this->setVar('maxFileSizeInformation', G::json_encode($inpuDocument->getMaxFileSize())); if ($debug) { if (!file_exists(PATH_HTML . "lib-dev/pmUI/build.cache")) { diff --git a/workflow/engine/controllers/home.php b/workflow/engine/controllers/home.php index 4feb31204..290e07545 100644 --- a/workflow/engine/controllers/home.php +++ b/workflow/engine/controllers/home.php @@ -1,6 +1,7 @@ render(); } + /** + * Get the cases information + * + * @param string $type + * @param integer $start + * @param integer $limit + * @param string $user + * @param string $filter + * @param string $search + * @param string $process + * @param string $status + * @param string $dateFrom + * @param string $dateTo + * @param string $callback + * @param string $dir + * @param string $sort + * @param string $category + * @return array + * + * @see \Home->appAdvancedSearch() + * @see \Home->appList() + * @see \Home->getApps() + */ public function getAppsData( $type, $start = null, @@ -404,10 +428,10 @@ class Home extends Controller $solrEnabled = false; if (( - $type == "todo" || $type == "draft" || $type == "paused" || $type == "sent" || - $type == "selfservice" || $type == "unassigned" || $type == "search" - ) && - (($solrConf = System::solrEnv()) !== false) + $type == "todo" || $type == "draft" || $type == "paused" || $type == "sent" || + $type == "selfservice" || $type == "unassigned" || $type == "search" + ) && + (($solrConf = System::solrEnv()) !== false) ) { $ApplicationSolrIndex = new AppSolr( $solrConf["solr_enabled"], @@ -443,21 +467,21 @@ class Home extends Controller $category ); } else { - $dataList['userId'] = $user; - $dataList['userUid'] = $this->userUid; - $dataList['start'] = $start; - $dataList['limit'] = $limit; - $dataList['filter'] = $filter; - $dataList['search'] = $search; - $dataList['process'] = $process; - $dataList['status'] = $status; + $dataList['userId'] = $user; + $dataList['userUid'] = $this->userUid; + $dataList['start'] = $start; + $dataList['limit'] = $limit; + $dataList['filter'] = $filter; + $dataList['search'] = $search; + $dataList['process'] = $process; + $dataList['status'] = $status; $dataList['dateFrom'] = $dateFrom; - $dataList['dateTo'] = $dateTo; + $dataList['dateTo'] = $dateTo; $dataList['callback'] = $callback; - $dataList['dir'] = $dir; - $dataList['sort'] = $sort; + $dataList['dir'] = $dir; + $dataList['sort'] = $sort; $dataList['category'] = $category; - $dataList['action'] = $type; + $dataList['action'] = $type; $dataList['dir'] = 'DESC'; /*----------------------------------********---------------------------------*/ if (true) { @@ -527,8 +551,9 @@ class Home extends Controller $generalConfCasesList = $conf->getConfiguration('ENVIRONMENT_SETTINGS', ''); $cases['data'][$i]['DEL_DELEGATE_DATE'] = ''; if (!empty(config("system.workspace"))) { - if (isset( $generalConfCasesList['casesListDateFormat'] ) && ! empty( $generalConfCasesList['casesListDateFormat'] )) { - $cases['data'][$i]['DEL_DELEGATE_DATE'] = $conf->getSystemDate($row['DEL_DELEGATE_DATE'], 'casesListDateFormat'); + if (isset($generalConfCasesList['casesListDateFormat']) && !empty($generalConfCasesList['casesListDateFormat'])) { + $cases['data'][$i]['DEL_DELEGATE_DATE'] = $conf->getSystemDate($row['DEL_DELEGATE_DATE'], + 'casesListDateFormat'); } } if ($cases['data'][$i]['DEL_DELEGATE_DATE'] == '') { @@ -542,6 +567,12 @@ class Home extends Controller $notes = $appNotes->getNotesList($row['APP_UID'], '', $notesStart, $notesLimit); $notes = AppNotes::applyHtmlentitiesInNotes($notes); + $iterator = 0; + foreach ($notes['array']['notes'] as $val) { + $notes ['array']['notes'][$iterator]['NOTE_DATE'] = DateTime::convertUtcToTimeZone($val['NOTE_DATE']); + $iterator++; + } + $notes = $notes['array']; $cases['data'][$i]['NOTES_COUNT'] = $notes['totalCount']; diff --git a/workflow/engine/controllers/pmTablesProxy.php b/workflow/engine/controllers/pmTablesProxy.php index 798271ccd..e55c7e852 100644 --- a/workflow/engine/controllers/pmTablesProxy.php +++ b/workflow/engine/controllers/pmTablesProxy.php @@ -11,8 +11,9 @@ use ProcessMaker\Core\System; use ProcessMaker\Validation\ExceptionRestApi; use ProcessMaker\Validation\ValidationUploadedFiles; -header("Content-type: text/html;charset=utf-8"); -require_once 'classes/model/AdditionalTables.php'; +//We need to suppress the error for the unittest that use this function +@header("Content-type: text/html;charset=utf-8"); + class pmTablesProxy extends HttpProxyController { @@ -404,7 +405,6 @@ class pmTablesProxy extends HttpProxyController $this->className = $table['ADD_TAB_CLASS_NAME']; $this->classPeerName = $this->className . 'Peer'; $sPath = PATH_DB . config("system.workspace") . PATH_SEP . 'classes' . PATH_SEP; - if (! file_exists( $sPath . $this->className . '.php' )) { throw new Exception( 'Update:: ' . G::loadTranslation( 'ID_PMTABLE_CLASS_DOESNT_EXIST', $this->className ) ); } @@ -427,7 +427,6 @@ class pmTablesProxy extends HttpProxyController if ($result) { G::auditLog("UpdateDataPmtable", "Table Name: ".$table['ADD_TAB_NAME']." Table ID: (".$table['ADD_TAB_UID'].") "); } - $this->success = $result; $this->message = $result ? G::loadTranslation( 'ID_UPDATED_SUCCESSFULLY' ) : G::loadTranslation( 'ID_UPDATE_FAILED' ); } @@ -725,7 +724,7 @@ class pmTablesProxy extends HttpProxyController } try { - ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) { + ValidationUploadedFiles::getValidationUploadedFiles()->dispatch(function($validator) { throw new ExceptionRestApi($validator->getMessage()); }); $result = new stdClass(); @@ -1094,32 +1093,38 @@ class pmTablesProxy extends HttpProxyController /** * Update data from a addTable record * - * @param $row + * @param array $row + * @param array $primaryKeys + * @return boolean + * @throws Exception + * + * @see workflow/engine/controllers/pmTablesProxy::dataUpdate() + * @link https://wiki.processmaker.com/3.2/PM_Tables */ - public function _dataUpdate ($row, $primaryKeys) + public function _dataUpdate($row, $primaryKeys) { - $keys = G::decrypt( $row['__index__'], 'pmtable' ); - $keys = explode( ',', $keys ); - unset( $row['__index__'] ); + $keys = G::decrypt($row['__index__'], 'pmtable'); + $keys = explode(',', $keys); + unset($row['__index__']); - $params = array (); + $params = []; foreach ($keys as $key) { - $params[] = is_numeric( $key ) ? $key : "'$key'"; + $params[] = is_int($key) ? (int)$key : (string)$key; } - $obj = null; - eval( '$obj = ' . $this->classPeerName . '::retrieveByPk(' . implode( ',', $params ) . ');' ); - - if (is_object( $obj )) { + $className = $this->classPeerName; + $obj = call_user_func_array($className . "::retrieveByPk", $params); + if (is_object($obj)) { foreach ($row as $key => $value) { // validation, don't modify primary keys - if (in_array( $key, $primaryKeys )) { - throw new Exception( G::loadTranslation( 'ID_DONT_MODIFY_PK_VALUE', array ($key - ) ) ); + if (in_array($key, $primaryKeys)) { + throw new Exception(G::loadTranslation('ID_DONT_MODIFY_PK_VALUE', [ + $key + ])); } - $action = 'set' . AdditionalTables::getPHPName( $key ); - $obj->$action( $value ); + $action = 'set' . AdditionalTables::getPHPName($key); + $obj->$action($value); } if ($r = $obj->validate()) { $obj->save(); @@ -1129,7 +1134,7 @@ class pmTablesProxy extends HttpProxyController foreach ($obj->getValidationFailures() as $objValidationFailure) { $msg .= $objValidationFailure->getMessage() . "\n"; } - throw new Exception( $msg ); + throw new Exception($msg); } } else { $result = false; @@ -1141,22 +1146,25 @@ class pmTablesProxy extends HttpProxyController /** * Update data from a addTable record * - * @param $row + * @param array $row + * @return boolean + * @see workflow/engine/controllers/pmTablesProxy::dataDestroy() + * @link https://wiki.processmaker.com/3.2/PM_Tables */ - public function _dataDestroy ($row) + public function _dataDestroy($row) { - $row = G::decrypt( $row, 'pmtable' ); - $row = str_replace( '"', '', $row ); - $keys = explode( ',', $row ); - $params = array (); + $row = G::decrypt($row, 'pmtable'); + $row = str_replace('"', '', $row); + $keys = explode(',', $row); + $params = []; foreach ($keys as $key) { - $params[] = is_numeric( $key ) ? $key : "'$key'"; + $params[] = is_int($key) ? (int)$key : (string)$key; } - $obj = null; - eval( '$obj = ' . $this->classPeerName . '::retrieveByPk(' . implode( ',', $params ) . ');' ); + $className = $this->classPeerName; + $obj = call_user_func_array($className . "::retrieveByPk", $params); - if (is_object( $obj )) { + if (is_object($obj)) { $obj->delete(); return true; } else { diff --git a/workflow/engine/data/mysql/insert.sql b/workflow/engine/data/mysql/insert.sql index a7cd4f3e4..76ccc6c07 100644 --- a/workflow/engine/data/mysql/insert.sql +++ b/workflow/engine/data/mysql/insert.sql @@ -57451,6 +57451,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ) VALUES ( 'LABEL','ID_CASE_REACTIVATED_SUCCESSFULLY','en','The case {APP_NUMBER} was reactivated successfully!','2014-01-15') , +( 'LABEL','ID_CASE_RESPONSE_NOT_AVAILABLE','en','No response available, please review the case information','2018-03-02') , ( 'LABEL','ID_CASE_ROUTED_TO','en','Case routed to','2017-06-02') , ( 'LABEL','ID_CASE_SCHEDULER','en','Case Scheduler','2014-01-15') , ( 'LABEL','ID_CASE_SCHEDULER_CLASSIC','en','Case Scheduler (classic processes)','2017-10-13') , @@ -59382,6 +59383,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ID_MAFE_9925fd3c9d09e862da22c5d6912420d9','en','End event must have an incoming sequence flow', NOW()) , ( 'LABEL','ID_MAFE_992d1d47106d77216cd6c3a15415dbea','en','Screenshot640', NOW()) , ( 'LABEL','ID_MAFE_99493c187e709deb387b6ee3ec6c8179','en','The input document is required, please select the value.', NOW()) , +( 'LABEL','ID_MAFE_99567b953da8beace4e3e7296bf1fc23','en','Assign type', NOW()) , ( 'LABEL','ID_MAFE_99b2439e63f73ad515f7ab2447a80673','en','PAUSED', NOW()) , ( 'LABEL','ID_MAFE_99c293babcada00063dd86b4f53bccd7','en','Variable sent in email', NOW()) , ( 'LABEL','ID_MAFE_9a0364b9e99bb480dd25e1f0284c8555','en','content', NOW()) , @@ -59447,6 +59449,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ID_MAFE_a603905470e2a5b8c13e96b579ef0dba','en','Debug', NOW()) , ( 'LABEL','ID_MAFE_a60852f204ed8028c1c58808b746d115','en','Ok', NOW()) , ( 'LABEL','ID_MAFE_a60cf2ece5b3e294aa794916477ac6a8','en','Notify the assigned user to this task', NOW()) , +( 'LABEL','ID_MAFE_a6122a65eaa676f700ae68d393054a37','en','Start', NOW()) , ( 'LABEL','ID_MAFE_a6527af0da63377b07a3effae750a485','en','
Triggers: Create scripts.', NOW()) , ( 'LABEL','ID_MAFE_a6c0580005d36b8ad4194b3b31cdb9ee','en','Input Document deleted successfully', NOW()) , ( 'LABEL','ID_MAFE_a6ca4597da3795aed1b1fa92f0e8d9a6','en','Previous Decade', NOW()) , @@ -59588,6 +59591,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ID_MAFE_c53385d51221bcb27c5f37de31043c24','en','No Category', NOW()) , ( 'LABEL','ID_MAFE_c5bcf625cbb751aba886be634ef4ef47','en','Invalid Connection between elements', NOW()) , ( 'LABEL','ID_MAFE_c5d84b6c19cb058b7b5471b30e926823','en','Invalid operation: Delete message flow before converting it to', NOW()) , +( 'LABEL','ID_MAFE_c5e54f7804fa817826dfa5ecc13cd92f','en','Last User Name', NOW()) , ( 'LABEL','ID_MAFE_c5f93fd19468533ea5c9114801c2958d','en','Input Document updated successfully', NOW()) , ( 'LABEL','ID_MAFE_c61404957758dfda283709e89376ab3e','en','layout', NOW()) , ( 'LABEL','ID_MAFE_c61dee25881b22ead46aca2bc70f0f9d','en','Assigned supervisors list', NOW()) , @@ -59732,6 +59736,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ID_MAFE_e2627d9094274c7bcdc01ce1dadbaaab','en','Select Target Process', NOW()) , ( 'LABEL','ID_MAFE_e29d57981d438d31f08b968bb12ed568','en','Select a Control', NOW()) , ( 'LABEL','ID_MAFE_e2a990c9958b0fd2ecb860335737c258','en','Please configure script to wait for a signal.', NOW()) , +( 'LABEL','ID_MAFE_e2ac1703ae8a4bb8b146f7337a7e4cab','en','Last User', NOW()) , ( 'LABEL','ID_MAFE_e2b9d6eb9f3ec7d4e6089274a4481fab','en','There are problems getting the list of DynaForms, please try again.', NOW()) , ( 'LABEL','ID_MAFE_e30f555e5a24f076a5d5be70a4625270','en','TNS', NOW()) , ( 'LABEL','ID_MAFE_e3ce9b91bd7b1be415b5e687006ad179','en','false: No default selection
true: current date
year: the first day of the current year
month: the first day of the month
day: the current day
hour: the current hour without minutes
minute: the current minute', NOW()) , @@ -59814,6 +59819,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ID_MAFE_f3a29486bed19a90f2da6d007818b427','en','Steps', NOW()) , ( 'LABEL','ID_MAFE_f3b92fc0f97f128818cfb44321376bca','en','Assignment', NOW()) , ( 'LABEL','ID_MAFE_f45c3a0bb3687ed8e221253b3fd4a2ce','en','EXCLUSIVE', NOW()) , +( 'LABEL','ID_MAFE_f45fabda0c6a595f709b3996398132f5','en','Diverging gateways expect to receive only one incoming flow.', NOW()) , ( 'LABEL','ID_MAFE_f4636507ca93332f92f92fb219a43b02','en','Database Connection', NOW()) , ( 'LABEL','ID_MAFE_f49b52022300199128ed01380edda751','en','There are problems updating the Timer Event, please try again.', NOW()) , ( 'LABEL','ID_MAFE_f4ae7ce97eda9edfe1541b3fdea115b6','en','Group or User', NOW()) , @@ -60741,6 +60747,11 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ID_SEARCH_RESULT','en','Search results','2014-01-15') , ( 'LABEL','ID_SEARCH_USER','en','Username','2014-01-15') , ( 'LABEL','ID_SEARCH_XML_METADATA','en','Search XML metadata','2014-01-15') , +( 'LABEL','ID_SEARCHING','en','Searching...','2019-05-03') , +( 'LABEL','ID_SEARCHING_CANCEL_MESSAGE','en','We are still gathering your search results. This may take a while based on your search criteria. You may cancel this search at any time','2019-05-03') , +( 'LABEL','ID_SEARCHING_TIME_OUT','en','Your search timed out','2019-05-03') , +( 'LABEL','ID_SEARCHING_UNEXPECTED_ERROR','en','An unexpected error occurred while searching for your results. Error Code {0} and Please contact your administrator.','2019-05-03') , +( 'LABEL','ID_SEARCHING_UNEXPECTED_ERROR_DEFAULT','en','An unexpected error occurred while searching for your results. Please contact your administrator.','2019-05-15') , ( 'LABEL','ID_SECOND','en','Second','2014-01-15') , ( 'LABEL','ID_SECONDS','en','Seconds','2014-01-15') , ( 'LABEL','ID_SECOND_FIGURE','en','Second Graph','2015-03-09') , @@ -61035,6 +61046,8 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ID_THERE_PROBLEM_SENDING_EMAIL','en','There was a problem sending the email to','2016-04-08') , ( 'LABEL','ID_THE_APPLICATION_IS_NOT_CANCELED','en','Error: The application {0} is not canceled.','2016-06-15') , ( 'LABEL','ID_THE_DEFAULT_CONFIGURATION','en','The default configuration was not defined','2016-11-16') , +( 'LABEL','ID_THE_FILE_SIZE_IS_BIGGER_THAN_THE_MAXIMUM_ALLOWED','en','The file size is bigger than the maximum allowed, the maximum size allowed is {0} Mbytes.','2019-02-26') , +( 'LABEL','ID_THE_MAXIMUM_VALUE_OF_THIS_FIELD_IS','en','The maximum value of this field is {0}.','2019-02-26') , ( 'LABEL','ID_THE_MIMETYPE_EXTENSION_ERROR','en','The mime type does not correspond to the permitted extension, please verify your file.','2018-10-2') , ( 'LABEL','ID_THE_NAME_CHANGE_MAY_CAUSE_DATA_LOSS','en','The change might cause data loss in the PM table. Do you want to continue?','2017-03-30') , ( 'LABEL','ID_THE_PHP_FILES_EXECUTION_WAS_DISABLED','en','The PHP files execution was disabled please contact the system administrator.','2018-04-20') , @@ -61096,7 +61109,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ID_TO','en','To','2014-01-15') , ( 'LABEL','ID_TODAY','en','Today','2014-01-15') , ( 'LABEL','ID_TOOLS','en','Tools','2014-01-15') , -( 'LABEL','ID_TOO_MANY_REQUESTS','en','Too many requests','2018-04-25') , +( 'LABEL','ID_TOO_MANY_REQUESTS','en','Upon configurations, you have reached the maximum number of files to upload.','2018-12-17') , ( 'LABEL','ID_TOP_MARGIN','en','Top Margin','2014-01-15') , ( 'LABEL','ID_TOTAL_CASES','en','Total Cases','2014-01-15') , ( 'LABEL','ID_TOTAL_CASES_REASSIGNED','en','Total Cases Reassigned','2014-01-15') , diff --git a/workflow/engine/js/strategicDashboard/viewDashboardPresenter.js b/workflow/engine/js/strategicDashboard/viewDashboardPresenter.js index 6267ccca1..6feca5d67 100644 --- a/workflow/engine/js/strategicDashboard/viewDashboardPresenter.js +++ b/workflow/engine/js/strategicDashboard/viewDashboardPresenter.js @@ -373,7 +373,7 @@ ViewDashboardPresenter.prototype.statusViewModel = function(indicatorId, data) { }; var newObject3 = { datalabel : originalObject.taskTitle, - value : 100 - (originalObject.percentageTotalOverdue + originalObject.percentageTotalAtRisk) + value : originalObject.percentageTotalOnTime }; if (newObject1.value > 0) { diff --git a/workflow/engine/js/strategicDashboard/viewDashboardView.js b/workflow/engine/js/strategicDashboard/viewDashboardView.js index 80fe40471..1f456d1ee 100644 --- a/workflow/engine/js/strategicDashboard/viewDashboardView.js +++ b/workflow/engine/js/strategicDashboard/viewDashboardView.js @@ -494,7 +494,7 @@ var loadIndicator = function (indicatorId, initDate, endDate) { fillSpecialIndicatorFirstView(viewModel); break; case "1050": - //fillStatusIndicatorFirstView(viewModel); + fillStatusIndicatorFirstView(viewModel); break; default: fillGeneralIndicatorFirstView(viewModel); diff --git a/workflow/engine/menus/caseOptions.php b/workflow/engine/menus/caseOptions.php index 1c3016f2c..cef29279c 100644 --- a/workflow/engine/menus/caseOptions.php +++ b/workflow/engine/menus/caseOptions.php @@ -1,26 +1,12 @@ . - * - * For more information, contact Colosa Inc, 2566 Le Jeune Rd., - * Coral Gables, FL, 33134, USA, or email info@colosa.com. + * @see Ajax::getCaseMenu() + * @see cases/cases_CatchSelfService.php + * @see cases/Cases_Resume.php * + * @link https://wiki.processmaker.com/3.2/Cases/Running_Cases */ global $G_TMP_MENU; global $sStatus; @@ -73,16 +59,17 @@ switch ($_SESSION['actionCaseOptions']) { unset($_SESSION['actionCaseOptions']); if ((($sStatus === 'DRAFT') || ($sStatus === 'TO_DO')) && !$statusSendAndUnassigned) { - if (isset($_SESSION['bNoShowSteps'])) { - unset($_SESSION['bNoShowSteps']); - } else { - if ($viewSteps === true) { - $G_TMP_MENU->AddIdOption('STEPS', G::LoadTranslation('ID_STEPS'), 'javascript:showSteps();', 'absolute'); - } - $G_TMP_MENU->AddIdOption('INFO', G::LoadTranslation('ID_INFORMATION'), 'javascript:showInformation();', 'absolute'); + //Menu: Steps + if ($viewSteps === true) { + $G_TMP_MENU->AddIdOption('STEPS', G::LoadTranslation('ID_STEPS'), 'javascript:showSteps();', 'absolute'); } + //Menu: Information + $G_TMP_MENU->AddIdOption('INFO', G::LoadTranslation('ID_INFORMATION'), 'javascript:showInformation();', 'absolute'); + //Menu: Actions $G_TMP_MENU->AddIdOption('ACTIONS', G::LoadTranslation('ID_ACTIONS'), 'javascript:showActions();', 'absolute'); } else { + //Menu: Information $G_TMP_MENU->AddIdOption('INFO', G::LoadTranslation('ID_INFORMATION'), 'javascript:showInformation();', 'absolute'); } +//Menu: Cases Notes $G_TMP_MENU->AddIdOption('NOTES', G::LoadTranslation('ID_NOTES'), 'javascript:showNotes();', 'absolute'); diff --git a/workflow/engine/methods/appFolder/appFolderAjax.php b/workflow/engine/methods/appFolder/appFolderAjax.php index 33072d250..e7ef06ae5 100644 --- a/workflow/engine/methods/appFolder/appFolderAjax.php +++ b/workflow/engine/methods/appFolder/appFolderAjax.php @@ -1446,7 +1446,7 @@ function checkTree($uidOriginFolder, $uidNewFolder) */ function uploadExternalDocument() { - ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) { + ValidationUploadedFiles::getValidationUploadedFiles()->dispatch(function($validator) { $response = [ 'error' => $validator->getMessage(), 'message' => $validator->getMessage(), diff --git a/workflow/engine/methods/cases/ajaxListener.php b/workflow/engine/methods/cases/ajaxListener.php index 183764b50..6b64382cf 100644 --- a/workflow/engine/methods/cases/ajaxListener.php +++ b/workflow/engine/methods/cases/ajaxListener.php @@ -394,6 +394,12 @@ class Ajax print(G::json_encode($processData)); } + /** + * Get the task information of the current task + * + * @see workflow/engine/templates/cases/open->taskInformation() + * @link https://wiki.processmaker.com/3.3/Cases/Information#Task_Information + */ public function getTaskInformation() { if (!isset($_SESSION['USER_LOGGED'])) { @@ -408,7 +414,15 @@ class Ajax if ($_SESSION['TASK'] == '-1') { $_SESSION['TASK'] = $_SESSION['CURRENT_TASK']; } - $taskData = $task->getDelegatedTaskData($_SESSION['TASK'], $_SESSION['APPLICATION'], $_SESSION['INDEX']); + + $arrayTaskUid = explode('|', $_SESSION['TASK']); + + if (count($arrayTaskUid) > 1) { + $arrayTaskUid = array_unique($arrayTaskUid); + } + $taskUid = $arrayTaskUid[0]; + + $taskData = $task->getDelegatedTaskData($taskUid, $_SESSION['APPLICATION'], $_SESSION['INDEX']); $taskData = \ProcessMaker\Util\DateTime::convertUtcToTimeZone($taskData); diff --git a/workflow/engine/methods/cases/caseMessageHistory_Ajax.php b/workflow/engine/methods/cases/caseMessageHistory_Ajax.php index 6e4c60fee..8f86eb4f6 100644 --- a/workflow/engine/methods/cases/caseMessageHistory_Ajax.php +++ b/workflow/engine/methods/cases/caseMessageHistory_Ajax.php @@ -1,6 +1,7 @@ xssFilterHard($_POST); @@ -85,6 +86,7 @@ switch ($actionAjax) { if ($respMess == 'BLOCK' || $respMess == '') { $appMessageArray[$index]['APP_MSG_BODY'] = ''; } + $appMessageArray[$index]['APP_MSG_DATE'] = DateTime::convertUtcToTimeZone($appMessageArray[$index]['APP_MSG_DATE']); $messageList[] = array_merge($appMessageArray[$index], ['MSGS_HISTORY' => $respMess]); } } diff --git a/workflow/engine/methods/cases/caseNotesAjax.php b/workflow/engine/methods/cases/caseNotesAjax.php index fcc30a088..b2781388d 100644 --- a/workflow/engine/methods/cases/caseNotesAjax.php +++ b/workflow/engine/methods/cases/caseNotesAjax.php @@ -1,4 +1,8 @@ addExtJsScript('app/main', true); $oHeadPublisher->addExtJsScript('cases/casesList', false); //adding a javascript file .js $oHeadPublisher->addContent('cases/casesListExtJs'); //adding a html file .html. $oHeadPublisher->assign('FORMATS', $c->getFormats()); -$oHeadPublisher->assign('extJsViewState', $oHeadPublisher->getExtJsViewState()); +$oHeadPublisher->assign('userUid', $userUid); +$oHeadPublisher->assign('extJsViewState', $oHeadPublisher->getExtJsViewState($userUid)); $oHeadPublisher->assign('isIE', Bootstrap::isIE()); $oHeadPublisher->assign('__OPEN_APPLICATION_UID__', $openApplicationUid); diff --git a/workflow/engine/methods/cases/cases_Ajax.php b/workflow/engine/methods/cases/cases_Ajax.php index 823fa5734..399ab523b 100644 --- a/workflow/engine/methods/cases/cases_Ajax.php +++ b/workflow/engine/methods/cases/cases_Ajax.php @@ -1,6 +1,7 @@ xssFilterHard($_GET); @@ -581,6 +582,7 @@ switch (($_POST['action']) ? $_POST['action'] : $_REQUEST['action']) { while ($rs->next()) { $result = $rs->getRow(); $result["TYPE"] = (array_key_exists($result["TYPE"], $arrayToTranslation)) ? $arrayToTranslation[$result["TYPE"]] : $result["TYPE"]; + $result['CREATE_DATE'] = DateTime::convertUtcToTimeZone($result['CREATE_DATE']); $aProcesses[] = $result; } @@ -622,7 +624,7 @@ switch (($_POST['action']) ? $_POST['action'] : $_REQUEST['action']) { $result["FILEDOCEXIST"] = ($result["FILEDOC"]); $result["FILEPDFEXIST"] = ($result["FILEPDF"]); $result["DELETE_FILE"] = (isset($result['ID_DELETE']) && $result['ID_DELETE'] == 'Delete') ? true : false; - + $result['CREATE_DATE'] = DateTime::convertUtcToTimeZone($result['CREATE_DATE']); $aProcesses[] = $result; $rs->next(); diff --git a/workflow/engine/methods/cases/cases_CatchSelfService.php b/workflow/engine/methods/cases/cases_CatchSelfService.php index 4c7f1f55f..4789df1de 100644 --- a/workflow/engine/methods/cases/cases_CatchSelfService.php +++ b/workflow/engine/methods/cases/cases_CatchSelfService.php @@ -1,103 +1,112 @@ . - * - * For more information, contact Colosa Inc, 2566 Le Jeune Rd., - * Coral Gables, FL, 33134, USA, or email info@colosa.com. - */ -/* Permissions */ + +use ProcessMaker\Util\DateTime; + switch ($RBAC->userCanAccess('PM_CASES')) { - case - 2: + case -2: G::SendTemporalMessage('ID_USER_HAVENT_RIGHTS_SYSTEM', 'error', 'labels'); G::header('location: ../login/login'); die(); break; - case - 1: + case -1: G::SendTemporalMessage('ID_USER_HAVENT_RIGHTS_PAGE', 'error', 'labels'); G::header('location: ../login/login'); die(); break; } -$oCase = new Cases(); -$Fields = $oCase->loadCase($_SESSION['APPLICATION'], $_SESSION['INDEX']); - -/* Render page */ +/** Render page */ require_once 'classes/model/Process.php'; require_once 'classes/model/Task.php'; +//Get information about the case +$case = new Cases(); +$fieldsCase = $case->loadCase($_SESSION['APPLICATION'], $_SESSION['INDEX']); + +//Get the user logged +$userLogged = isset($RBAC->aUserInfo['USER_INFO']['USR_UID']) ? $RBAC->aUserInfo['USER_INFO']['USR_UID'] : ''; + +//Check the authorization +$objCase = new \ProcessMaker\BusinessModel\Cases(); +$userCanAccess = $objCase->userAuthorization( + $userLogged, + $fieldsCase['PRO_UID'], + $fieldsCase['APP_UID'], + ['PM_ALLCASES'], + ['SUMMARY_FORM' => 'VIEW'] +); + $objProc = new Process(); -$aProc = $objProc->load($Fields['PRO_UID']); -$Fields['PRO_TITLE'] = $aProc['PRO_TITLE']; +$fieldsProcess = $objProc->load($fieldsCase['PRO_UID']); +$fieldsCase['PRO_TITLE'] = $fieldsProcess['PRO_TITLE']; -$objTask = new Task(); -$aTask = $objTask->load($Fields['TAS_UID']); -$Fields['TAS_TITLE'] = $aTask['TAS_TITLE']; +if ( + isset($fieldsProcess['PRO_DYNAFORMS']['PROCESS']) && + !empty($fieldsProcess['PRO_DYNAFORMS']['PROCESS']) && + $userCanAccess['objectPermissions']['SUMMARY_FORM'] && + $objProc->isBpmnProcess($fieldsCase['PRO_UID']) +) { + /**We will to show the custom summary form only for BPMN process*/ + $_REQUEST['APP_UID'] = $fieldsCase['APP_UID']; + $_REQUEST['DEL_INDEX'] = $fieldsCase['DEL_INDEX']; + $_REQUEST['DYN_UID'] = $fieldsProcess['PRO_DYNAFORMS']['PROCESS']; + require_once(PATH_METHODS . 'cases' . PATH_SEP . 'summary.php'); + exit(); +} else { + /**We will to show the default claim case form*/ + $objTask = new Task(); + $fieldsTask = $objTask->load($fieldsCase['TAS_UID']); + $fieldsCase['TAS_TITLE'] = $fieldsTask['TAS_TITLE']; + $fieldsCase['STATUS'] .= ' ( ' . G::LoadTranslation('ID_UNASSIGNED') . ' )'; -$Fields['STATUS'] .= ' ( ' . G::LoadTranslation('ID_UNASSIGNED') . ' )'; + //Now getting information about the PREVIOUS task. If is the first task then no previous, use 1 + $appDelegation = new AppDelegation(); + $appDelegation->Load( + $fieldsCase['APP_UID'], + ($fieldsCase['DEL_PREVIOUS'] == 0 ? $fieldsCase['DEL_PREVIOUS'] = 1 : $fieldsCase['DEL_PREVIOUS']) + ); + $fieldsDelegation = $appDelegation->toArray(BasePeer::TYPE_FIELDNAME); -//now getting information about the PREVIOUS task. If is the first task then no preious, use 1 -$oAppDel = new AppDelegation(); -$oAppDel->Load($Fields['APP_UID'], ($Fields['DEL_PREVIOUS'] == 0 ? $Fields['DEL_PREVIOUS'] = 1 : $Fields['DEL_PREVIOUS'])); + try { + $userInfo = new Users(); + $userInfo->load($fieldsDelegation['USR_UID']); + $fieldsCase['PREVIOUS_USER'] = $userInfo->getUsrFirstname() . ' ' . $userInfo->getUsrLastname(); + } catch (Exception $error) { + $fieldsCase['PREVIOUS_USER'] = G::LoadTranslation('ID_NO_PREVIOUS_USR_UID'); + } -$aAppDel = $oAppDel->toArray(BasePeer::TYPE_FIELDNAME); -try { - $oCurUser = new Users(); - $oCurUser->load($aAppDel['USR_UID']); - $Fields['PREVIOUS_USER'] = $oCurUser->getUsrFirstname() . ' ' . $oCurUser->getUsrLastname(); -} catch (Exception $oError) { - $Fields['PREVIOUS_USER'] = G::LoadTranslation('ID_NO_PREVIOUS_USR_UID'); -} - -$objTask = new Task(); -$aTask = $objTask->load($aAppDel['TAS_UID']); -$Fields['PREVIOUS_TASK'] = $aTask['TAS_TITLE']; - -//To enable information (dynaforms, steps) before claim a case -$_SESSION['bNoShowSteps'] = true; -$G_MAIN_MENU = 'processmaker'; -$G_SUB_MENU = 'caseOptions'; -$G_ID_MENU_SELECTED = 'CASES'; -$G_ID_SUB_MENU_SELECTED = '_'; -$oHeadPublisher = headPublisher::getSingleton(); -$oHeadPublisher->addScriptCode(" -if (typeof parent != 'undefined') { - if (parent.showCaseNavigatorPanel) { - parent.showCaseNavigatorPanel('{$Fields['APP_STATUS']}'); - } -}"); -$oHeadPublisher->addScriptCode(' - var Cse = {}; - Cse.panels = {}; - var leimnud = new maborak(); - leimnud.make(); - leimnud.Package.Load("rpc,drag,drop,panel,app,validator,fx,dom,abbr",{Instance:leimnud,Type:"module"}); - leimnud.Package.Load("cases",{Type:"file",Absolute:true,Path:"/jscore/cases/core/cases.js"}); - leimnud.Package.Load("cases_Step",{Type:"file",Absolute:true,Path:"/jscore/cases/core/cases_Step.js"}); - leimnud.Package.Load("processmap",{Type:"file",Absolute:true,Path:"/jscore/processmap/core/processmap.js"}); - leimnud.exec(leimnud.fix.memoryLeak); + //To enable information (dynaforms, steps) before claim a case + $_SESSION['bNoShowSteps'] = true; + $G_MAIN_MENU = 'processmaker'; + $G_SUB_MENU = 'caseOptions'; + $G_ID_MENU_SELECTED = 'CASES'; + $G_ID_SUB_MENU_SELECTED = '_'; + $headPublisher = headPublisher::getSingleton(); + $headPublisher->addScriptCode(" + if (typeof parent != 'undefined') { + if (parent.showCaseNavigatorPanel) { + parent.showCaseNavigatorPanel('{$fieldsCase['APP_STATUS']}'); + } + } + "); + $headPublisher->addScriptCode(' + var Cse = {}; + Cse.panels = {}; + var leimnud = new maborak(); + leimnud.make(); + leimnud.Package.Load("rpc,drag,drop,panel,app,validator,fx,dom,abbr",{Instance:leimnud,Type:"module"}); + leimnud.Package.Load("cases",{Type:"file",Absolute:true,Path:"/jscore/cases/core/cases.js"}); + leimnud.Package.Load("cases_Step",{Type:"file",Absolute:true,Path:"/jscore/cases/core/cases_Step.js"}); + leimnud.Package.Load("processmap",{Type:"file",Absolute:true,Path:"/jscore/processmap/core/processmap.js"}); + leimnud.exec(leimnud.fix.memoryLeak); '); -$oHeadPublisher = headPublisher::getSingleton(); -$oHeadPublisher->addScriptFile('/jscore/cases/core/cases_Step.js'); + $headPublisher = headPublisher::getSingleton(); + $headPublisher->addScriptFile('/jscore/cases/core/cases_Step.js'); -$Fields['isIE'] = Bootstrap::isIE(); + $fieldsCase['isIE'] = Bootstrap::isIE(); -$G_PUBLISH = new Publisher(); -$G_PUBLISH->AddContent('xmlform', 'xmlform', 'cases/cases_CatchSelfService.xml', '', $Fields, 'cases_CatchExecute'); -G::RenderPage('publish', 'blank'); + $G_PUBLISH = new Publisher(); + $fieldsCase = DateTime::convertUtcToTimeZone($fieldsCase); + $G_PUBLISH->AddContent('xmlform', 'xmlform', 'cases/cases_CatchSelfService.xml', '', $fieldsCase, 'cases_CatchExecute'); + G::RenderPage('publish', 'blank'); +} diff --git a/workflow/engine/methods/cases/cases_Derivate.php b/workflow/engine/methods/cases/cases_Derivate.php index ebc7909ff..6b227d636 100644 --- a/workflow/engine/methods/cases/cases_Derivate.php +++ b/workflow/engine/methods/cases/cases_Derivate.php @@ -318,8 +318,8 @@ try { try { if(top.opener) { top.opener.location.reload(); - top.close(); } + top.close(); } catch(e) { } "; diff --git a/workflow/engine/methods/cases/cases_Open.php b/workflow/engine/methods/cases/cases_Open.php index 8e79f67b2..bdba04b22 100644 --- a/workflow/engine/methods/cases/cases_Open.php +++ b/workflow/engine/methods/cases/cases_Open.php @@ -2,24 +2,17 @@ /** * cases_Open.php * - * ProcessMaker Open Source Edition - * Copyright (C) 2004 - 2008 Colosa Inc. + * @see cases/casesList.js + * @see cases/cases_Step.php + * @see cases/cases_CatchSelfService.php + * @see cases/derivatedGmail.php + * @see cases/open.php + * @see controllers/Home::indexSingle() + * @see controllers/Home::startCase() + * @see pmGmail/sso.php + * @see webentry/access.php * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * For more information, contact Colosa Inc, 2566 Le Jeune Rd., - * Coral Gables, FL, 33134, USA, or email info@colosa.com. + * @link https://wiki.processmaker.com/3.2/Cases/Cases#Search_Criteria */ if(isset( $_GET['gmail']) && $_GET['gmail'] == 1){ @@ -50,7 +43,8 @@ try { //Loading data for a Jump request if (!isset($_GET['APP_UID']) && isset($_GET['APP_NUMBER'])) { $_GET['APP_UID'] = $caseInstance->getApplicationUIDByNumber( $_GET['APP_NUMBER'] ); - $_GET['DEL_INDEX'] = $caseInstance->getCurrentDelegation( $_GET['APP_UID'], $_SESSION['USER_LOGGED'] ); + //Get the index related to the userLogged but this thread can be OPEN or CLOSED + $_GET['DEL_INDEX'] = $caseInstance->getCurrentDelegation($_GET['APP_UID'], $_SESSION['USER_LOGGED']); //if the application doesn't exist if (is_null($_GET['APP_UID'])) { @@ -67,87 +61,86 @@ try { } } - $sAppUid = $_GET['APP_UID']; - $iDelIndex = $_GET['DEL_INDEX']; - $_action = isset($_GET['action']) ? $_GET['action'] : ''; + $appUid = $_GET['APP_UID']; + $delIndex = $_GET['DEL_INDEX']; + $action = isset($_GET['action']) ? $_GET['action'] : ''; //loading application data - $aFields = $caseInstance->loadCase( $sAppUid, $iDelIndex ); + $fieldCase = $caseInstance->loadCase($appUid, $delIndex); if (!isset($_SESSION['CURRENT_TASK'])) { - $_SESSION['CURRENT_TASK'] = $aFields['TAS_UID']; + $_SESSION['CURRENT_TASK'] = $fieldCase['TAS_UID']; } elseif ($_SESSION['CURRENT_TASK'] == '') { - $_SESSION['CURRENT_TASK'] = $aFields['TAS_UID']; + $_SESSION['CURRENT_TASK'] = $fieldCase['TAS_UID']; } unset($_SESSION['ACTION']); $flagJump = ''; - if ($_action == 'jump') { + if ($action == 'jump') { $_SESSION['ACTION'] = 'jump'; $flagJump = 1; } - switch ($aFields['APP_STATUS']) { + switch ($fieldCase['APP_STATUS']) { case 'DRAFT': case 'TO_DO': //Check if the case is in pause, check a valid record in table APP_DELAY - $isPaused = AppDelay::isPaused($sAppUid, $iDelIndex); + $isPaused = AppDelay::isPaused($appUid, $delIndex); //Check if the case is a waiting for a SYNCHRONOUS subprocess - $subAppData = new \SubApplication(); - $caseSubprocessPending = $subAppData->isSubProcessWithCasePending($sAppUid, $iDelIndex); + $subAppData = new SubApplication(); + $caseSubprocessPending = $subAppData->isSubProcessWithCasePending($appUid, $delIndex); if ($isPaused || $caseSubprocessPending) { //the case is paused show only the resume - $_SESSION['APPLICATION'] = $sAppUid; - $_SESSION['INDEX'] = $iDelIndex; - $_SESSION['PROCESS'] = $aFields['PRO_UID']; - $_SESSION['TASK'] = - 1; + $_SESSION['APPLICATION'] = $appUid; + $_SESSION['INDEX'] = $delIndex; + $_SESSION['PROCESS'] = $fieldCase['PRO_UID']; + $_SESSION['TASK'] = -1; $_SESSION['STEP_POSITION'] = 0; - $_SESSION['CURRENT_TASK'] = $aFields['TAS_UID']; + $_SESSION['CURRENT_TASK'] = $fieldCase['TAS_UID']; - require_once (PATH_METHODS . 'cases' . PATH_SEP . 'cases_Resume.php'); + require_once(PATH_METHODS . 'cases' . PATH_SEP . 'cases_Resume.php'); exit(); } /** * these routine is to verify if the case was acceded from advanced search list */ - - if ($_action == 'search') { + if ($action == 'search') { //verify if the case is with the current user - $aData = AppDelegation::getCurrentUsers($sAppUid, $iDelIndex); - if ($aData['USR_UID'] !== $_SESSION['USER_LOGGED'] && !empty($aData['USR_UID'])) { + $delegationUsers = AppDelegation::getCurrentUsers($appUid, $delIndex); + if ($delegationUsers['USR_UID'] !== $_SESSION['USER_LOGGED'] && !empty($delegationUsers['USR_UID'])) { //distinct "" for selfservice //so we show just the resume $_SESSION['alreadyDerivated'] = true; - $_SESSION['APPLICATION'] = $sAppUid; - $_SESSION['INDEX'] = $iDelIndex; - $_SESSION['PROCESS'] = $aFields['PRO_UID']; - $_SESSION['TASK'] = - 1; + $_SESSION['APPLICATION'] = $appUid; + $_SESSION['INDEX'] = $delIndex; + $_SESSION['PROCESS'] = $fieldCase['PRO_UID']; + $_SESSION['TASK'] = -1; $_SESSION['STEP_POSITION'] = 0; - require_once (PATH_METHODS . 'cases' . PATH_SEP . 'cases_Resume.php'); + require_once(PATH_METHODS . 'cases' . PATH_SEP . 'cases_Resume.php'); exit(); } } - //proceed and try to open the case - $oAppDelegation = new AppDelegation(); - $aDelegation = $oAppDelegation->load( $sAppUid, $iDelIndex ); + //Proceed and try to open the case + $appDelegation = new AppDelegation(); + $delegationInfo = $appDelegation->load($appUid, $delIndex); - //if there are no user in the delegation row, this case is in selfservice - if ($aDelegation['USR_UID'] == "") { - $_SESSION['APPLICATION'] = $sAppUid; - $_SESSION['INDEX'] = $iDelIndex; - $_SESSION['PROCESS'] = $aFields['PRO_UID']; - $_SESSION['TASK'] = - 1; + //If there are no user in the delegation row, this case is in selfservice + if (empty($delegationInfo['USR_UID'])) { + $_SESSION['APPLICATION'] = $appUid; + $_SESSION['INDEX'] = $delIndex; + $_SESSION['PROCESS'] = $fieldCase['PRO_UID']; + $_SESSION['TASK'] = -1; $_SESSION['STEP_POSITION'] = 0; - $_SESSION['CURRENT_TASK'] = $aFields['TAS_UID']; + $_SESSION['CURRENT_TASK'] = $fieldCase['TAS_UID']; - //if the task is in the valid selfservice tasks for this user, then catch the case, else just view the resume - if ($caseInstance->isSelfService($_SESSION['USER_LOGGED'], $aFields['TAS_UID'], $sAppUid)) { + //If the task is in the valid selfservice tasks for this user, then catch the case, else just view the resume + if ($caseInstance->isSelfService($_SESSION['USER_LOGGED'], $fieldCase['TAS_UID'], $appUid)) { require_once(PATH_METHODS . 'cases' . PATH_SEP . 'cases_CatchSelfService.php'); } else { require_once(PATH_METHODS . 'cases' . PATH_SEP . 'cases_Resume.php'); @@ -156,49 +149,56 @@ try { exit(); } - //If the current users is in the AppDelegation row, then open the case - if (($aDelegation['USR_UID'] == $_SESSION['USER_LOGGED']) && $_action != 'sent') { - $_SESSION['APPLICATION'] = $sAppUid; - $_SESSION['INDEX'] = $iDelIndex; + //If the current users is in the AppDelegation row and the thread is open will be open the case + if (($delegationInfo['USR_UID'] == $_SESSION['USER_LOGGED'] && $delegationInfo['DEL_THREAD_STATUS'] === 'OPEN') + && $action != 'sent') + { + $_SESSION['APPLICATION'] = $appUid; + $_SESSION['INDEX'] = $delIndex; - if (is_null( $aFields['DEL_INIT_DATE'] )) { - $caseInstance->setDelInitDate( $sAppUid, $iDelIndex ); - $aFields = $caseInstance->loadCase( $sAppUid, $iDelIndex ); + if (is_null($fieldCase['DEL_INIT_DATE'])) { + $caseInstance->setDelInitDate($appUid, $delIndex); + $fieldCase = $caseInstance->loadCase($appUid, $delIndex); } - $_SESSION['PROCESS'] = $aFields['PRO_UID']; - $_SESSION['TASK'] = $aFields['TAS_UID']; + $_SESSION['PROCESS'] = $fieldCase['PRO_UID']; + $_SESSION['TASK'] = $fieldCase['TAS_UID']; $_SESSION['STEP_POSITION'] = 0; /* Redirect to next step */ - unset( $_SESSION['bNoShowSteps'] ); + unset($_SESSION['bNoShowSteps']); - /* Execute Before Triggers for first Task*/ - $caseInstance->getExecuteTriggerProcess($sAppUid, 'OPEN'); - /*end Execute Before Triggers for first Task*/ + /** Execute a trigger when a case is open */ + $caseInstance->getExecuteTriggerProcess($appUid, 'OPEN'); - $aNextStep = $caseInstance->getNextStep( $_SESSION['PROCESS'], $_SESSION['APPLICATION'], $_SESSION['INDEX'], $_SESSION['STEP_POSITION'] ); - $sPage = $aNextStep['PAGE']; - G::header( 'location: ' . $sPage ); + $nextStep = $caseInstance->getNextStep( + $_SESSION['PROCESS'], + $_SESSION['APPLICATION'], + $_SESSION['INDEX'], + $_SESSION['STEP_POSITION'] + ); + $pageOpenCase = $nextStep['PAGE']; + + G::header('location: ' . $pageOpenCase); } else { - $_SESSION['APPLICATION'] = $sAppUid; - $_SESSION['PROCESS'] = $aFields['PRO_UID']; - $_SESSION['TASK'] = - 1; + $_SESSION['APPLICATION'] = $appUid; + $_SESSION['PROCESS'] = $fieldCase['PRO_UID']; + $_SESSION['TASK'] = -1; $_SESSION['bNoShowSteps'] = 1; $_SESSION['STEP_POSITION'] = 0; //When the case have another user or current user doesn't have rights to this self-service, //Just view the case Resume - if ($_action === 'search' || $_action === 'to_reassign') { + if ($action === 'search' || $action === 'to_reassign') { //We need to use the index sent with the corresponding record - $_SESSION['INDEX'] = $iDelIndex; + $_SESSION['INDEX'] = $delIndex; } else { //Get DEL_INDEX $criteria = new Criteria('workflow'); $criteria->addSelectColumn(AppDelegationPeer::DEL_INDEX); - $criteria->add(AppDelegationPeer::APP_UID, $sAppUid); - $criteria->add(AppDelegationPeer::DEL_LAST_INDEX , 1); + $criteria->add(AppDelegationPeer::APP_UID, $appUid); + $criteria->add(AppDelegationPeer::DEL_LAST_INDEX, 1); $rs = AppDelegationPeer::doSelectRS($criteria); $rs->setFetchmode(ResultSet::FETCHMODE_ASSOC); $rs->next(); @@ -206,29 +206,29 @@ try { $_SESSION['INDEX'] = $row['DEL_INDEX']; } - $Fields = $caseInstance->loadCase($_SESSION['APPLICATION'], $_SESSION['INDEX'], $flagJump); + $fields = $caseInstance->loadCase($_SESSION['APPLICATION'], $_SESSION['INDEX'], $flagJump); + $_SESSION['CURRENT_TASK'] = $fields['TAS_UID']; - $_SESSION['CURRENT_TASK'] = $Fields['TAS_UID']; - require_once (PATH_METHODS . 'cases' . PATH_SEP . 'cases_Resume.php'); + require_once(PATH_METHODS . 'cases' . PATH_SEP . 'cases_Resume.php'); } break; default: //APP_STATUS IS COMPLETED OR CANCELLED - $_SESSION['APPLICATION'] = $sAppUid; - $_SESSION['INDEX'] = $caseInstance->getCurrentDelegationCase( $_GET['APP_UID'] ); - $_SESSION['PROCESS'] = $aFields['PRO_UID']; - $_SESSION['TASK'] = - 1; + $_SESSION['APPLICATION'] = $appUid; + $_SESSION['INDEX'] = $caseInstance->getCurrentDelegationCase($_GET['APP_UID']); + $_SESSION['PROCESS'] = $fieldCase['PRO_UID']; + $_SESSION['TASK'] = -1; $_SESSION['STEP_POSITION'] = 0; - $Fields = $caseInstance->loadCase($_SESSION['APPLICATION'], $_SESSION['INDEX'], $flagJump); - $_SESSION['CURRENT_TASK'] = $Fields['TAS_UID']; + $fields = $caseInstance->loadCase($_SESSION['APPLICATION'], $_SESSION['INDEX'], $flagJump); + $_SESSION['CURRENT_TASK'] = $fields['TAS_UID']; - require_once (PATH_METHODS . 'cases' . PATH_SEP . 'cases_Resume.php'); + require_once(PATH_METHODS . 'cases' . PATH_SEP . 'cases_Resume.php'); } } catch (Exception $e) { - $aMessage = array (); - $aMessage['MESSAGE'] = $e->getMessage(); + $message = []; + $message['MESSAGE'] = $e->getMessage(); $G_PUBLISH = new Publisher(); - $G_PUBLISH->AddContent( 'xmlform', 'xmlform', 'login/showMessage', '', $aMessage ); - G::RenderPage( 'publishBlank', 'blank' ); + $G_PUBLISH->AddContent('xmlform', 'xmlform', 'login/showMessage', '', $message); + G::RenderPage('publishBlank', 'blank'); } diff --git a/workflow/engine/methods/cases/cases_Resume.php b/workflow/engine/methods/cases/cases_Resume.php index bcb72fe9b..cc37baf88 100644 --- a/workflow/engine/methods/cases/cases_Resume.php +++ b/workflow/engine/methods/cases/cases_Resume.php @@ -1,6 +1,7 @@ userCanAccess('PM_CASES')) { @@ -123,6 +124,7 @@ if ($nTasksInParallel > 1) { } $Fields['TAS_TITLE'] = $aTask['TAS_TITLE']; +$Fields = DateTime::convertUtcToTimeZone($Fields); $objUser = new Users(); $oHeadPublisher = headPublisher::getSingleton(); @@ -150,10 +152,10 @@ if ($Fields['APP_STATUS'] != 'COMPLETED') { $FieldsPar['CURRENT_USER'] = ''; } } - $FieldsPar['DEL_DELEGATE_DATE'] = $row['DEL_DELEGATE_DATE']; - $FieldsPar['DEL_INIT_DATE'] = $row['DEL_INIT_DATE']; - $FieldsPar['DEL_TASK_DUE_DATE'] = $row['DEL_TASK_DUE_DATE']; - $FieldsPar['DEL_FINISH_DATE'] = $row['DEL_FINISH_DATE']; + $FieldsPar['DEL_DELEGATE_DATE'] = DateTime::convertUtcToTimeZone($row['DEL_DELEGATE_DATE']); + $FieldsPar['DEL_INIT_DATE'] = DateTime::convertUtcToTimeZone($row['DEL_INIT_DATE']); + $FieldsPar['DEL_TASK_DUE_DATE'] = DateTime::convertUtcToTimeZone($row['DEL_TASK_DUE_DATE']); + $FieldsPar['DEL_FINISH_DATE'] = DateTime::convertUtcToTimeZone($row['DEL_FINISH_DATE']); $G_PUBLISH->AddContent('xmlform', 'xmlform', 'cases/cases_Resume_Current_Task.xml', '', $FieldsPar); } } diff --git a/workflow/engine/methods/cases/cases_SaveData.php b/workflow/engine/methods/cases/cases_SaveData.php index d37f30f47..fe69df0c2 100644 --- a/workflow/engine/methods/cases/cases_SaveData.php +++ b/workflow/engine/methods/cases/cases_SaveData.php @@ -1,26 +1,7 @@ . - * - * For more information, contact Colosa Inc, 2566 Le Jeune Rd., - * Coral Gables, FL, 33134, USA, or email info@colosa.com. - */ + +use ProcessMaker\Validation\ValidationUploadedFiles; + //validate the data post if (!isset($_SESSION['USER_LOGGED'])) { if(!strpos($_SERVER['REQUEST_URI'], 'gmail')) { @@ -70,29 +51,15 @@ if (!isset($_SESSION['USER_LOGGED'])) { } /** - * If you can, you may want to set post_max_size to a low value (say 1M) to make - * testing easier. First test to see how your script behaves. Try uploading a file - * that is larger than post_max_size. If you do you will get a message like this - * in your error log: - * - * [09-Jun-2010 19:28:01] PHP Warning: POST Content-Length of 30980857 bytes exceeds - * the limit of 2097152 bytes in Unknown on line 0 - * - * This makes the script is not completed. - * - * Solving the problem: - * The PHP documentation http://php.net/manual/en/ini.core.php#ini.post-max-size - * provides a hack to solve this problem: - * - * If the size of post data is greater than post_max_size, the $_POST and $_FILES - * superglobals are empty. + * To do: The following evaluation must be moved after saving the data (so as not to lose the data entered in the form). + * It only remains because it is an old behavior, which must be defined by "Product Owner". + * @see workflow/engine/methods/services/ActionsByEmailDataFormPost.php */ -if ($_SERVER['REQUEST_METHOD'] == 'POST' && empty($_POST) && empty($_FILES) && $_SERVER['CONTENT_LENGTH'] > 0) { - $aMessage = array(); - $aMessage['MESSAGE'] = G::loadTranslation('ID_UPLOAD_ERR_INI_SIZE'); - $G_PUBLISH = new Publisher(); - $G_PUBLISH->AddContent('xmlform', 'xmlform', 'login/showMessage', '', $aMessage); - G::RenderPage('publish', 'blank'); +$validator = ValidationUploadedFiles::getValidationUploadedFiles()->runRulesForFileEmpty(); +if ($validator->fails()) { + G::SendMessageText($validator->getMessage(), "ERROR"); + $url = explode("sys" . config("system.workspace"), $_SERVER['HTTP_REFERER']); + G::header("location: " . "/sys" . config("system.workspace") . $url[1]); die(); } diff --git a/workflow/engine/methods/cases/cases_ShowOutputDocument.php b/workflow/engine/methods/cases/cases_ShowOutputDocument.php index a275d143f..a824cc55d 100644 --- a/workflow/engine/methods/cases/cases_ShowOutputDocument.php +++ b/workflow/engine/methods/cases/cases_ShowOutputDocument.php @@ -77,8 +77,8 @@ if (defined('DISABLE_DOWNLOAD_DOCUMENTS_SESSION_VALIDATION') && DISABLE_DOWNLOAD } } - -$info = pathinfo($oAppDocument->getAppDocFilename()); +$docFileName = fixContentDispositionFilename($oAppDocument->getAppDocFilename()); +$info = pathinfo($docFileName); if (!isset($_GET['ext'])) { $ext = $info['extension']; } else { @@ -133,7 +133,7 @@ if (!$sw_file_exists) { $res['message'] = $info['basename'] . $ver . '.' . $ext; print G::json_encode($res); } else { - $nameFile = G::inflect($info['basename'] . $ver) . '.' . $ext; + $nameFile = $info['basename'] . $ver . '.' . $ext; $licensedFeatures = PMLicensedFeatures::getSingleton(); $downloadStatus = false; /*----------------------------------********---------------------------------*/ diff --git a/workflow/engine/methods/cases/cases_Step.php b/workflow/engine/methods/cases/cases_Step.php index fd11b5bf3..ff9ceec99 100644 --- a/workflow/engine/methods/cases/cases_Step.php +++ b/workflow/engine/methods/cases/cases_Step.php @@ -444,7 +444,8 @@ try { } //END: If there is a Break Step registered from Plugin - $sFilenameOriginal = $sFilename = preg_replace('[^A-Za-z0-9_]', '_', G::replaceDataField($aOD['OUT_DOC_FILENAME'], $Fields['APP_DATA'])); + $outDocFile = replacePrefixes($aOD['OUT_DOC_FILENAME']); + $sFilenameOriginal = $sFilename = preg_replace('[^A-Za-z0-9_]', '_', G::replaceDataField($outDocFile, $Fields['APP_DATA'])); //Get the Custom Folder ID (create if necessary) $oFolder = new AppFolder(); @@ -1009,7 +1010,7 @@ try { $aFields['TASK'][$sKey]['NEXT_TASK']['ROU_PREVIOUS_TYPE'] = ''; } if (isset($aValues['ROU_CONDITION'])) { - $aFields['TASK'][$sKey]['NEXT_TASK']['ROU_CONDITION'] = ''; + $aFields['TASK'][$sKey]['NEXT_TASK']['ROU_CONDITION'] = ''; } if (isset($aValues['SOURCE_UID'])) { $aFields['TASK'][$sKey]['NEXT_TASK']['SOURCE_UID'] = ''; diff --git a/workflow/engine/methods/cases/debug_triggers.php b/workflow/engine/methods/cases/debug_triggers.php index 6fa6a9df3..328fd0c8a 100644 --- a/workflow/engine/methods/cases/debug_triggers.php +++ b/workflow/engine/methods/cases/debug_triggers.php @@ -1,65 +1,57 @@ $name) { + foreach ($trigger['TRIGGERS_NAMES'] as $index => $name) { $triggersList[$i]['name'] = $name; - $triggersList[$i]['execution_time'] = strtolower( $aTrigger['TIME'] ); - //$t_code = $aTrigger['TRIGGERS_VALUES'][$index]['TRI_WEBBOT']; - //$t_code = str_replace('"', '\'',$t_code); - //$t_code = addslashes($t_code); - //$t_code = Only1br($t_code); - //highlighting the trigger code using the geshi third party library + $triggersList[$i]['execution_time'] = strtolower($trigger['TIME']); - $geshi = new GeSHi( $aTrigger['TRIGGERS_VALUES'][$index]['TRI_WEBBOT'], 'php' ); - $geshi->enable_line_numbers( GESHI_FANCY_LINE_NUMBERS, 2 ); - $geshi->set_line_style( 'background: #f0f0f0;' ); + $geshi = new GeSHi($trigger['TRIGGERS_VALUES'][$index]['TRI_WEBBOT'], 'php'); + $geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS, 2); + $geshi->set_line_style('background: #f0f0f0;'); - $triggersList[$i]['code'] = $geshi->parse_code(); //$aTrigger['TRIGGERS_VALUES'][$index]['TRI_WEBBOT']; + $triggersList[$i]['code'] = $geshi->parse_code(); - $triggerUid = $aTrigger['TRIGGERS_VALUES'][$index]['TRI_UID']; - $triggersList[$i]['script_execution_time'] = isset($aTrigger['TRIGGERS_EXECUTION_TIME'][$triggerUid]) ? $aTrigger['TRIGGERS_EXECUTION_TIME'][$triggerUid] : ''; + $triggerUid = $trigger['TRIGGERS_VALUES'][$index]['TRI_UID']; + $triggersList[$i]['script_execution_time'] = isset($trigger['TRIGGERS_EXECUTION_TIME'][$triggerUid]) ? $trigger['TRIGGERS_EXECUTION_TIME'][$triggerUid] : ''; - $i ++; + $i++; } - } else { - } } -//print_r($_SESSION['TRIGGER_DEBUG']['ERRORS']); die; -$DEBUG_ERRORS = array_unique( $_SESSION['TRIGGER_DEBUG']['ERRORS'] ); +$debugErrors = array_unique($_SESSION['TRIGGER_DEBUG']['ERRORS'], SORT_REGULAR); -foreach ($DEBUG_ERRORS as $error) { - if (isset( $error['ERROR'] ) and $error['ERROR'] != '') { +foreach ($debugErrors as $error) { + if (isset($error['ERROR']) and $error['ERROR'] != '') { $triggersList[$i]['name'] = 'Error'; $triggersList[$i]['execution_time'] = 'error'; $triggersList[$i]['code'] = $error['ERROR']; - $i ++; + $i++; } - if (isset( $error['FATAL'] ) and $error['FATAL'] != '') { - $error['FATAL'] = str_replace( "
", "\n", $error['FATAL'] ); - $tmp = explode( "\n", $error['FATAL'] ); - $triggersList[$i]['name'] = isset( $tmp[0] ) ? $tmp[0] : 'Fatal Error in trigger'; + if (isset($error['FATAL']) and $error['FATAL'] != '') { + $error['FATAL'] = str_replace("
", "\n", $error['FATAL']); + $tmp = explode("\n", $error['FATAL']); + $triggersList[$i]['name'] = isset($tmp[0]) ? $tmp[0] : 'Fatal Error in trigger'; $triggersList[$i]['execution_time'] = 'Fatal error'; $triggersList[$i]['code'] = $error['FATAL']; - $i ++; + $i++; } } $triggersRet = new StdClass(); -$triggersRet->total = count( $triggersList ); +$triggersRet->total = count($triggersList); $triggersRet->data = $triggersList; -echo G::json_encode( $triggersRet ); +echo G::json_encode($triggersRet); diff --git a/workflow/engine/methods/cases/main_init.php b/workflow/engine/methods/cases/main_init.php index dd8fc7950..42da23301 100644 --- a/workflow/engine/methods/cases/main_init.php +++ b/workflow/engine/methods/cases/main_init.php @@ -9,6 +9,8 @@ $oHeadPublisher->addContent("cases/main"); //Adding a html file .html. $keyMem = "USER_PREFERENCES" . $_SESSION["USER_LOGGED"]; $memcache = PMmemcached::getSingleton(config("system.workspace")); +$openCaseIE = false; + if (($arrayConfig = $memcache->get($keyMem)) === false) { $conf->loadConfig($x, "USER_PREFERENCES", "", "", $_SESSION["USER_LOGGED"], ""); $arrayConfig = $conf->aConfig; @@ -86,6 +88,7 @@ if (isset($_SESSION['__OPEN_APPLICATION_UID__'])) { if (count($arrayDelIndex) === 1) { //We will to open the case: one thread + $openCaseIE = true; $defaultOption = '../cases/open?APP_UID=' . $openAppUid . '&DEL_INDEX=' . $arrayDelIndex[0] . '&action=' . $action; } else { //We will to show the list: more than one thread @@ -117,6 +120,7 @@ $urlProxy = 'casesMenuLoader?action=getAllCountersEnterprise&r='; $oHeadPublisher->assign('regionTreePanel', $regionTreePanel); $oHeadPublisher->assign('regionDebug', $regionDebug); +$oHeadPublisher->assign('openCaseIE', $openCaseIE); $oHeadPublisher->assign("defaultOption", $defaultOption); //User menu permissions $oHeadPublisher->assign('urlProxy', $urlProxy); //sending the urlProxy to make $oHeadPublisher->assign("_nodeId", isset($confDefaultOption) ? $confDefaultOption : "PM_USERS"); //User menu permissions @@ -162,4 +166,4 @@ function getAuthorizationCode($client) return $code; } -/*----------------------------------********---------------------------------*/ \ No newline at end of file +/*----------------------------------********---------------------------------*/ diff --git a/workflow/engine/methods/cases/open.php b/workflow/engine/methods/cases/open.php index 26ee94eec..c30ea1c4b 100644 --- a/workflow/engine/methods/cases/open.php +++ b/workflow/engine/methods/cases/open.php @@ -1,32 +1,21 @@ . - * - * For more information, contact Colosa Inc, 2566 Le Jeune Rd., - * Coral Gables, FL, 33134, USA, or email info@colosa.com. + * @link https://wiki.processmaker.com/3.2/Cases/Cases#Search_Criteria + * @link https://wiki.processmaker.com/3.2/Cases/Cases#Inbox + * @link https://wiki.processmaker.com/3.2/Cases/Cases#New_Case */ -/** - * - * @author Erik Amaru Ortiz - * @date Jan 3th, 2010 - */ +use ProcessMaker\BusinessModel\Cases as BmCases; +use ProcessMaker\BusinessModel\ProcessSupervisor; $tBarGmail = false; if (isset($_GET['gmail']) && $_GET['gmail'] == 1) { @@ -40,18 +29,18 @@ if (!isset($_GET['APP_UID']) && !isset($_GET['APP_NUMBER']) && !isset($_GET['DEL } //Get the APP_UID related to APP_NUMBER if (!isset($_GET['APP_UID']) && isset($_GET['APP_NUMBER'])) { - $oCase = new Cases(); - $appUid = $oCase->getApplicationUIDByNumber(htmlspecialchars($_GET['APP_NUMBER'])); + $caseInstance = new Cases(); + $appUid = $caseInstance->getApplicationUIDByNumber(htmlspecialchars($_GET['APP_NUMBER'])); if (is_null($appUid)) { throw new Exception(G::LoadTranslation('ID_CASE_DOES_NOT_EXISTS')); } } else { $appUid = htmlspecialchars($_GET['APP_UID']); } -//If we don't have the DEL_INDEX we get the current delIndex. Data reporting tool does not have this information +//If we don't have the DEL_INDEX we get the current delIndex for example data reporting tool and jump to if (!isset($_GET['DEL_INDEX'])) { - $oCase = new Cases(); - $delIndex = $oCase->getCurrentDelegation($appUid, $_SESSION['USER_LOGGED']); + $caseInstance = new Cases(); + $delIndex = $caseInstance->getCurrentDelegation($appUid, $_SESSION['USER_LOGGED']); if (is_null($delIndex)) { throw new Exception(G::LoadTranslation('ID_CASE_IS_CURRENTLY_WITH_ANOTHER_USER')); } @@ -62,13 +51,11 @@ if (!isset($_GET['DEL_INDEX'])) { $tasUid = (isset($_GET['TAS_UID'])) ? $tasUid = htmlspecialchars($_GET['TAS_UID']) : ''; -$oCase = new Cases(); +$caseInstance = new Cases(); $conf = new Configurations(); - -$oHeadPublisher = headPublisher::getSingleton(); +$headPublisher = headPublisher::getSingleton(); $urlToRedirectAfterPause = 'casesListExtJs'; - /*----------------------------------********---------------------------------*/ $licensedFeatures = PMLicensedFeatures::getSingleton(); if ($licensedFeatures->verifyfeature('7qhYmF1eDJWcEdwcUZpT0k4S0xTRStvdz09')) { @@ -80,70 +67,110 @@ if ($licensedFeatures->verifyfeature('7qhYmF1eDJWcEdwcUZpT0k4S0xTRStvdz09')) { } /*----------------------------------********---------------------------------*/ - -$oHeadPublisher->assign('urlToRedirectAfterPause', $urlToRedirectAfterPause); - - -$oHeadPublisher->addExtJsScript('app/main', true); -$oHeadPublisher->addExtJsScript('cases/open', true); -$oHeadPublisher->assign('FORMATS', $conf->getFormats()); +$headPublisher->assign('urlToRedirectAfterPause', $urlToRedirectAfterPause); +$headPublisher->addExtJsScript('app/main', true); +$headPublisher->addExtJsScript('cases/open', true); +$headPublisher->assign('FORMATS', $conf->getFormats()); $uri = ''; foreach ($_GET as $k => $v) { $uri .= ($uri == '') ? "$k=$v" : "&$k=$v"; } -if (isset($_GET['action']) && ($_GET['action'] == 'jump')) { - $oNewCase = new \ProcessMaker\BusinessModel\Cases(); - //We need to get the last index OPEN or CLOSED (by Paused cases) - //Set true because we need to check if the case is paused - $delIndex = $oNewCase->getOneLastThread($appUid, true); - $case = $oCase->loadCase($appUid, $delIndex, $_GET['action']); -} else { - $case = $oCase->loadCase($appUid, $delIndex); -} +/** + * @todo, the action over the case from Open Case, Case Link and jump to needs to work similar, we need to have a PRD + */ -if (isset($_GET['actionFromList']) && ($_GET['actionFromList'] === 'to_revise')) { - $oSupervisor = new \ProcessMaker\BusinessModel\ProcessSupervisor(); - $caseCanBeReview = $oSupervisor->reviewCaseStatusForSupervisor($appUid, $delIndex); - //Check if the case has the correct status for update the information from supervisor/review - if (!$caseCanBeReview) { - //The supervisor can not edit the information - $script = 'cases_Open?'; - } else { - //The supervisor can edit the information, the case are in TO_DO - $script = 'cases_OpenToRevise?APP_UID=' . $appUid . '&DEL_INDEX=' . $delIndex . '&TAS_UID=' . $tasUid; - $oHeadPublisher->assign('treeToReviseTitle', G::loadtranslation('ID_STEP_LIST')); - $casesPanelUrl = 'casesToReviseTreeContent?APP_UID=' . $appUid . '&DEL_INDEX=' . $delIndex; - $oHeadPublisher->assign('casesPanelUrl', $casesPanelUrl); //translations - echo "
"; +$case = $caseInstance->loadCase($appUid, $delIndex); +$canClaimCase = false; +$caseCanBeReview = false; +if (isset($_GET['action'])) { + switch ($_GET['action']) { + case 'todo': //Inbox + case 'draft': //Draft + case 'sent': //Participated + case 'unassigned': //Unassigned + case 'paused': //Paused + case 'search': //Advanced search + //For add the validation in the others list we need to a have a PRD, because is change of the functionality + break; + case 'to_reassign': //Reassign + //From reassign: Review if the user can be claim the case + if ($caseInstance->isSelfService($_SESSION['USER_LOGGED'], $case['TAS_UID'], $appUid)) { + $canClaimCase = true; + } + break; + case 'to_revise': //Review + $proSupervisor = new ProcessSupervisor(); + $caseCanBeReview = $proSupervisor->reviewCaseStatusForSupervisor($appUid, $delIndex); + break; + case 'jump': //Jump To action + //From Review: Review if the user is supervisor + if (isset($_GET['actionFromList']) && ($_GET['actionFromList'] === 'to_revise')) { + $proSupervisor = new ProcessSupervisor(); + $caseCanBeReview = $proSupervisor->reviewCaseStatusForSupervisor($appUid, $delIndex); + } + //From Unassigned: Review if the user can be claim the case + if ($caseInstance->isSelfService($_SESSION['USER_LOGGED'], $case['TAS_UID'], $appUid)) { + $canClaimCase = true; + } + //From Paused: Get the last index OPEN or CLOSED (by Paused cases) + $bmCases = new BmCases(); + $delIndex = $bmCases->getOneLastThread($appUid, true); + $case = $caseInstance->loadCase($appUid, $delIndex, $_GET['action']); + break; } -} else { +} + +/** + * Review if the user can be open the case from Review list + * @link https://wiki.processmaker.com/3.2/Cases/Process_Supervisor#Review + */ +if (!$caseCanBeReview) { + //The supervisor can not edit the information $script = 'cases_Open?'; +} else { + //The supervisor can edit the information, the case are in TO_DO + $script = 'cases_OpenToRevise?APP_UID=' . $appUid . '&DEL_INDEX=' . $delIndex . '&TAS_UID=' . $tasUid; + $headPublisher->assign('treeToReviseTitle', G::loadtranslation('ID_STEP_LIST')); + $casesPanelUrl = 'casesToReviseTreeContent?APP_UID=' . $appUid . '&DEL_INDEX=' . $delIndex; + $headPublisher->assign('casesPanelUrl', $casesPanelUrl); //translations + echo "
"; } -// getting bpmn projects -$c = new Criteria('workflow'); -$c->addSelectColumn(BpmnProjectPeer::PRJ_UID); -$ds = ProcessPeer::doSelectRS($c); -$ds->setFetchmode(ResultSet::FETCHMODE_ASSOC); -$bpmnProjects = array(); +$process = new Process(); +$fields = $process->load($case['PRO_UID']); +$isBpmn = $fields['PRO_BPMN'] === 1 ? true : false; -while ($ds->next()) { - $row = $ds->getRow(); - $bpmnProjects[] = $row['PRJ_UID']; +/** + * Review if the user can be open summary form + * @link https://wiki.processmaker.com/3.2/Case_Summary#Viewing_the_Custom_Dynaform_when_Opening_a_Case + */ +$showCustomForm = false; + +/*----------------------------------********---------------------------------*/ +$respView = $caseInstance->getAllObjectsFrom($case['PRO_UID'], $appUid, $case['TAS_UID'], $_SESSION['USER_LOGGED'], 'VIEW'); +$viewSummaryForm = isset($respView['SUMMARY_FORM']) && $respView['SUMMARY_FORM'] === 1 ? true : false; +$isNoEmpty = isset($fields['PRO_DYNAFORMS']['PROCESS']) && !empty($fields['PRO_DYNAFORMS']['PROCESS']); + +if ($isBpmn && $viewSummaryForm && $isNoEmpty) { + $showCustomForm = true; } -$oStep = new Step(); -$oStep = $oStep->loadByProcessTaskPosition($case['PRO_UID'], $case['TAS_UID'], 1); -$oHeadPublisher->assign('uri', $script . $uri); -$oHeadPublisher->assign('_APP_NUM', '#: ' . $case['APP_NUMBER']); -$oHeadPublisher->assign('_PROJECT_TYPE', in_array($case['PRO_UID'], $bpmnProjects) ? 'bpmn' : 'classic'); -$oHeadPublisher->assign('_PRO_UID', $case['PRO_UID']); -$oHeadPublisher->assign('_APP_UID', $appUid); -$oHeadPublisher->assign('_ENV_CURRENT_DATE', $conf->getSystemDate(date('Y-m-d'))); -$oHeadPublisher->assign('_ENV_CURRENT_DATE_NO_FORMAT', date('Y-m-d-h-i-A')); -$oHeadPublisher->assign('idfirstform', is_null($oStep) ? '-1' : $oStep->getStepUidObj()); -$oHeadPublisher->assign('appStatus', $case['APP_STATUS']); -$oHeadPublisher->assign('tbarGmail', $tBarGmail); +/*----------------------------------********---------------------------------*/ + +$step = new Step(); +$step = $step->loadByProcessTaskPosition($case['PRO_UID'], $case['TAS_UID'], 1); +$headPublisher->assign('uri', $script . $uri); +$headPublisher->assign('_APP_NUM', '#: ' . $case['APP_NUMBER']); +$headPublisher->assign('_PROJECT_TYPE', $isBpmn ? 'bpmn' : 'classic'); +$headPublisher->assign('_PRO_UID', $case['PRO_UID']); +$headPublisher->assign('_APP_UID', $appUid); +$headPublisher->assign('_ENV_CURRENT_DATE', $conf->getSystemDate(date('Y-m-d'))); +$headPublisher->assign('_ENV_CURRENT_DATE_NO_FORMAT', date('Y-m-d-h-i-A')); +$headPublisher->assign('idfirstform', is_null($step) ? '-1' : $step->getStepUidObj()); +$headPublisher->assign('appStatus', $case['APP_STATUS']); +$headPublisher->assign('tbarGmail', $tBarGmail); +$headPublisher->assign('showCustomForm', $showCustomForm); +$headPublisher->assign('canClaimCase', $canClaimCase); if (!isset($_SESSION['APPLICATION']) || !isset($_SESSION['TASK']) || !isset($_SESSION['INDEX'])) { $_SESSION['PROCESS'] = $case['PRO_UID']; diff --git a/workflow/engine/methods/cases/proxyCasesList.php b/workflow/engine/methods/cases/proxyCasesList.php index bfec0df59..0be7607f4 100644 --- a/workflow/engine/methods/cases/proxyCasesList.php +++ b/workflow/engine/methods/cases/proxyCasesList.php @@ -1,4 +1,9 @@ error = G::LoadTranslation('ID_LOGIN_AGAIN'); @@ -9,31 +14,59 @@ if (!isset($_SESSION['USER_LOGGED'])) { } +/** + * Do input filtering, although filtering should be done on the frontend rendering, not here + */ $filter = new InputFilter(); $_GET = $filter->xssFilterHard($_GET); $_REQUEST = $filter->xssFilterHard($_REQUEST); $_SESSION['USER_LOGGED'] = $filter->xssFilterHard($_SESSION['USER_LOGGED']); -//Getting the extJs parameters +// Callback in the UI to utilize $callback = isset($_REQUEST["callback"]) ? $_REQUEST["callback"] : "stcCallback1001"; -//This default value was defined in casesList.js -$dir = isset($_REQUEST["dir"]) ? $_REQUEST["dir"] : "DESC"; -//This default value was defined in casesList.js + +// Sort column $sort = isset($_REQUEST["sort"]) ? $_REQUEST["sort"] : "APP_NUMBER"; +// Sort direction +$dir = isset($_REQUEST["dir"]) ? $_REQUEST["dir"] : "DESC"; + +// Pagination control $start = !empty($_REQUEST["start"]) ? $_REQUEST["start"] : 0; $limit = !empty($_REQUEST["limit"]) ? $_REQUEST["limit"] : 25; + +// Our search filter $filter = isset($_REQUEST["filter"]) ? $_REQUEST["filter"] : ""; + +// What process $process = isset($_REQUEST["process"]) ? $_REQUEST["process"] : ""; + +// What category $category = isset($_REQUEST["category"]) ? $_REQUEST["category"] : ""; + +// What status $status = isset($_REQUEST["status"]) ? strtoupper($_REQUEST["status"]) : ""; $filterStatus = isset($_REQUEST["filterStatus"]) ? strtoupper($_REQUEST["filterStatus"]) : ""; + +// What user $user = isset($_REQUEST["user"]) ? $_REQUEST["user"] : ""; + +// What keywords to search $search = isset($_REQUEST["search"]) ? $_REQUEST["search"] : ""; + +// What kind of action $action = isset($_GET["action"]) ? $_GET["action"] : (isset($_REQUEST["action"]) ? $_REQUEST["action"] : "todo"); + +// What kind of search $type = isset($_GET["type"]) ? $_GET["type"] : (isset($_REQUEST["type"]) ? $_REQUEST["type"] : "extjs"); + +// Date ranges $dateFrom = isset($_REQUEST["dateFrom"]) ? substr($_REQUEST["dateFrom"], 0, 10) : ""; $dateTo = isset($_REQUEST["dateTo"]) ? substr($_REQUEST["dateTo"], 0, 10) : ""; + +// First? No idea $first = isset($_REQUEST["first"]) ? true : false; + + $openApplicationUid = (isset($_REQUEST['openApplicationUid']) && $_REQUEST['openApplicationUid'] != '') ? $_REQUEST['openApplicationUid'] : null; $search = (!is_null($openApplicationUid)) ? $openApplicationUid : $search; @@ -67,10 +100,8 @@ try { break; } - $apps = new Applications(); - if ($action == 'search') { - $data = $apps->searchAll( + $data = Delegation::search( $userUid, $start, $limit, @@ -85,7 +116,7 @@ try { $columnSearch ); } else { - $data = $apps->getAll( + $data = Delegation::search( $userUid, $start, $limit, diff --git a/workflow/engine/methods/cases/proxyPMTablesFieldList.php b/workflow/engine/methods/cases/proxyPMTablesFieldList.php index 75f6a25fc..4f7a3054a 100644 --- a/workflow/engine/methods/cases/proxyPMTablesFieldList.php +++ b/workflow/engine/methods/cases/proxyPMTablesFieldList.php @@ -1,7 +1,14 @@ $caseColumns, "caseReaderFields" => $caseReaderFields, "rowsperpage" => 20, "dateformat" => "M d, Y"); } +/** + * Get default configuration and verify if casesListDefaultFieldsAndConfig method exist. + * + * @param string $action + * @param int $translation + * @return array + * + * @see workflow/engine/methods/cases/proxyPMTablesFieldList.php + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ function getDefaultConfig($action, $translation) { $config = new Configurations(); @@ -335,6 +352,16 @@ function getDefaultConfig($action, $translation) return $arrayConfig; } +/** + * Get default fields configuration. + * + * @param string $action + * @param int $translation + * @return array + * + * @see workflow/engine/methods/cases/proxyPMTablesFieldList.php + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ function getDefaultFields($action, $translation) { $config = new Configurations(); @@ -405,6 +432,16 @@ function getDefaultFields($action, $translation) return $arrayField; } +/** + * Set available fields. + * + * @param array $arrayAvailableField + * @param array $arrayField + * @return array + * + * @see workflow/engine/methods/cases/proxyPMTablesFieldList.php + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ function setAvailableFields($arrayAvailableField, $arrayField) { $i = 0; @@ -427,6 +464,16 @@ function setAvailableFields($arrayAvailableField, $arrayField) return $arrayFieldResult; } +/** + * Set Cases List fields. + * + * @param array $arrayCasesListField + * @param array $arrayField + * @return array + * + * @see workflow/engine/methods/cases/proxyPMTablesFieldList.php + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ function setCasesListFields($arrayCasesListField, $arrayField) { $i = 0; @@ -462,32 +509,56 @@ function setCasesListFields($arrayCasesListField, $arrayField) return $arrayFieldResult; } +/** + * Get the Custom Case List configuration data. + * + * @global string $action + * @global array $confCasesList + * @global string $tabUid + * + * @see workflow/engine/methods/cases/proxyPMTablesFieldList.php + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ function fieldSet() { - global $conf; - global $confCasesList; global $action; + global $confCasesList; + global $tabUid; - if (is_array($confCasesList)) { - $validConfig = isset($confCasesList["first"]) && isset($confCasesList["second"]); - } else { - $validConfig = false; + $arrayField = getDefaultFields($action, 0); + $arrayConfig = getDefaultConfig($action, 0); + $result = genericJsonResponse($tabUid, [], $arrayField, $arrayConfig["rowsperpage"], $arrayConfig["dateformat"]); + $result['first']['data'] = getFieldsByTabUid($tabUid); + + $confCasesList = (array) $confCasesList; + + if (!empty($confCasesList)) { + if (!empty($tabUid) && empty($confCasesList['PMTable'])) { + $confCasesList['PMTable'] = $tabUid; + $confCasesList['first']['data'] = getFieldsByTabUid($tabUid); + } + if (!empty($confCasesList['PMTable']) && empty($tabUid)) { + $result = $confCasesList; + } } - if (!$validConfig) { - $arrayField = getDefaultFields($action, 0); - $arrayConfig = getDefaultConfig($action, 0); - - $result = genericJsonResponse("", array(), $arrayField, $arrayConfig["rowsperpage"], $arrayConfig["dateformat"]); - - $conf->saveObject($result, "casesList", $action, "", "", ""); - - echo G::json_encode($result); - } else { - echo G::json_encode($confCasesList); + if (is_array($result) && isset($result['second']['data'])) { + foreach ($result['second']['data'] as $key => $value) { + $result['second']['data'][$key]['align_label'] = $result['second']['data'][$key]['align']; + } } + echo G::json_encode($result); } +/** + * Reset fields configuration. + * + * @global string $action + * @param int $translation + * + * @see workflow/engine/methods/cases/proxyPMTablesFieldList.php + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ function fieldReset($translation) { global $action; @@ -500,6 +571,15 @@ function fieldReset($translation) echo G::json_encode($result); } +/** + * Complete a field. + * + * @global string $action + * @param int $translation + * + * @see workflow/engine/methods/cases/proxyPMTablesFieldList.php + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ function fieldComplete($translation) { @@ -565,6 +645,15 @@ function fieldComplete($translation) echo G::json_encode($result); } +/** + * Reset field label. + * + * @global string $action + * @param int $translation + * + * @see workflow/engine/methods/cases/proxyPMTablesFieldList.php + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ function fieldLabelReset($translation) { @@ -604,6 +693,15 @@ function fieldLabelReset($translation) echo G::json_encode($result); } +/** + * Save a field. + * + * @global object $conf + * @global string $action + * + * @see workflow/engine/methods/cases/proxyPMTablesFieldList.php + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ function fieldSave() { @@ -690,11 +788,6 @@ try { switch ($xaction) { case "FIELD_SET": - if (is_array($confCasesList) && isset($confCasesList['second']['data'])) { - foreach ($confCasesList['second']['data'] as $key => $value) { - $confCasesList['second']['data'][$key]['align_label'] = $confCasesList['second']['data'][$key]['align']; - } - } fieldSet(); break; case "FIELD_RESET": @@ -722,14 +815,20 @@ try { G::outRes( G::json_encode( G::LoadTranslation("ID_EXCEPTION_LOG_INTERFAZ", array($token)) ) ); } - /** - * set the generic Json Response, using two array for the grid stores and a string for the pmtable name - * @param string $pmtable - * @param array $first - * @param array $second - * @return $response a json string - */ -function genericJsonResponse($pmtable, $first, $second, $rowsperpage, $dateFormat) +/** + * Set the generic Json Response, using two array for the grid stores and a string for the pmtable name. + * + * @param string $pmtable + * @param array $first + * @param array $second + * @param array $rowsPerPage + * @param string $dateFormat + * @return array + * + * @see workflow/engine/methods/cases/proxyPMTablesFieldList.php + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ +function genericJsonResponse($pmtable, $first, $second, $rowsPerPage, $dateFormat) { $firstGrid['totalCount'] = count($first); $firstGrid['data'] = $first; @@ -739,54 +838,72 @@ function genericJsonResponse($pmtable, $first, $second, $rowsperpage, $dateForma $result['first'] = $firstGrid; $result['second'] = $secondGrid; $result['PMTable'] = isset($pmtable) ? $pmtable : ''; - $result['rowsperpage'] = isset($rowsperpage) ? $rowsperpage : 20; + $result['rowsperpage'] = isset($rowsPerPage) ? $rowsPerPage : 20; $result['dateformat'] = isset($dateFormat) && $dateFormat != '' ? $dateFormat : 'M d, Y'; return $result; } +/** + * Get row from PM Table. + * + * @param string $tabUid + * + * @see workflow/engine/methods/cases/proxyPMTablesFieldList.php + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ function xgetFieldsFromPMTable($tabUid) { - $rows = array(); - $result = array(); - // $rows[] = array ( 'name' => 'val 1', 'gridIndex' => '21', 'fieldType' => 'PM Table' ); - // $rows[] = array ( 'name' => 'val 2', 'gridIndex' => '22', 'fieldType' => 'PM Table' ); - // $rows[] = array ( 'name' => 'val 3', 'gridIndex' => '23', 'fieldType' => 'PM Table' ); - //$result['success'] = true; - //$result['totalCount'] = count($rows); - $oCriteria = new Criteria('workflow'); - $oCriteria->clearSelectColumns ( ); - $oCriteria->setDistinct(); - $oCriteria->addSelectColumn ( FieldsPeer::FLD_NAME ); - $oCriteria->addSelectColumn ( FieldsPeer::FLD_UID ); - $oCriteria->addSelectColumn ( FieldsPeer::FLD_INDEX ); - $oCriteria->add (FieldsPeer::ADD_TAB_UID, $tabUid , CRITERIA::EQUAL ); - $oCriteria->add (FieldsPeer::FLD_NAME, 'APP_UID' , CRITERIA::NOT_EQUAL ); - $oCriteria->addAnd (FieldsPeer::FLD_NAME, 'APP_NUMBER' , CRITERIA::NOT_EQUAL ); - $oCriteria->addDescendingOrderByColumn('FLD_INDEX'); - $oDataset = FieldsPeer::doSelectRS($oCriteria); - $oDataset->setFetchmode(ResultSet::FETCHMODE_ASSOC); - $oDataset->next(); - $index = count($rows); - - while ($aRow = $oDataset->getRow()) { - $aRow['index'] = ++$index; - $aTempRow['name'] = $aRow['FLD_NAME']; - $aTempRow['gridIndex'] = $aRow['index']; - $aTempRow['fieldType'] = 'PM Table'; - $rows[] = $aTempRow; - $oDataset->next(); - } - - $result['data'] = $rows; - print G::json_encode( $result ) ; + $result = []; + $result['data'] = getFieldsByTabUid($tabUid); + print G::json_encode($result); } - /** - * - * @param Array $fields - * @return Array - * - */ +/** + * Get rows from Fields table. + * + * @param string $tabUid + * @return array + * + * @see workflow/engine/methods/cases/proxyPMTablesFieldList.php + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ +function getFieldsByTabUid($tabUid) +{ + $rows = []; + $criteria = new Criteria('workflow'); + $criteria->clearSelectColumns(); + $criteria->setDistinct(); + $criteria->addSelectColumn(FieldsPeer::FLD_NAME); + $criteria->addSelectColumn(FieldsPeer::FLD_UID); + $criteria->addSelectColumn(FieldsPeer::FLD_INDEX); + $criteria->add(FieldsPeer::ADD_TAB_UID, $tabUid, CRITERIA::EQUAL); + $criteria->add(FieldsPeer::FLD_NAME, 'APP_UID', CRITERIA::NOT_EQUAL); + $criteria->addAnd(FieldsPeer::FLD_NAME, 'APP_NUMBER', CRITERIA::NOT_EQUAL); + $criteria->addDescendingOrderByColumn('FLD_INDEX'); + $dataSet = FieldsPeer::doSelectRS($criteria); + $dataSet->setFetchmode(ResultSet::FETCHMODE_ASSOC); + $dataSet->next(); + $index = 0; + while ($row = $dataSet->getRow()) { + $row['index'] = ++$index; + $tempRow['name'] = $row['FLD_NAME']; + $tempRow['gridIndex'] = $row['index']; + $tempRow['fieldType'] = 'PM Table'; + $rows[] = $tempRow; + $dataSet->next(); + } + return $rows; +} + +/** + * Calculate Grid index. + * + * @param array $fields + * @return array + * + * @see workflow/engine/methods/cases/proxyPMTablesFieldList.php + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ function calculateGridIndex($fields) { for ($i=0; $i. - * - * For more information, contact Colosa Inc, 2566 Le Jeune Rd., - * Coral Gables, FL, 33134, USA, or email info@colosa.com. - */ + +use ProcessMaker\Util\DateTime; try { global $RBAC; @@ -70,7 +50,7 @@ try { if ($result->next()) { $FieldsPmDynaform = $applicationFields; $FieldsPmDynaform["CURRENT_DYNAFORM"] = $_REQUEST['DYN_UID']; - $a = new PmDynaform(\ProcessMaker\Util\DateTime::convertUtcToTimeZone($FieldsPmDynaform)); + $a = new PmDynaform(DateTime::convertUtcToTimeZone($FieldsPmDynaform)); $a->printView(); } if (file_exists( PATH_DYNAFORM . $applicationFields['PRO_UID'] . PATH_SEP . $_REQUEST['DYN_UID'] . '.xml' )) { diff --git a/workflow/engine/methods/enterprise/addonsStoreAction.php b/workflow/engine/methods/enterprise/addonsStoreAction.php index 05ff152dd..bd66c230c 100644 --- a/workflow/engine/methods/enterprise/addonsStoreAction.php +++ b/workflow/engine/methods/enterprise/addonsStoreAction.php @@ -18,7 +18,7 @@ function runBgProcessmaker($task, $log) } try { - ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) { + ValidationUploadedFiles::getValidationUploadedFiles()->dispatch(function($validator) { throw new ExceptionRestApi($validator->getMessage()); }); if (isset($_REQUEST["action"])) { diff --git a/workflow/engine/methods/enterprise/pluginsImportFile.php b/workflow/engine/methods/enterprise/pluginsImportFile.php index 64939795f..627a66672 100644 --- a/workflow/engine/methods/enterprise/pluginsImportFile.php +++ b/workflow/engine/methods/enterprise/pluginsImportFile.php @@ -36,7 +36,7 @@ $response = array(); $status = 1; try { - ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) { + ValidationUploadedFiles::getValidationUploadedFiles()->dispatch(function($validator) { throw new Exception($validator->getMessage()); }); diff --git a/workflow/engine/methods/login/authentication.php b/workflow/engine/methods/login/authentication.php index 7f4770c7e..1fb2c0864 100644 --- a/workflow/engine/methods/login/authentication.php +++ b/workflow/engine/methods/login/authentication.php @@ -1,5 +1,7 @@ loadOrCreateIfNotExists($_SESSION['USER_LOGGED'], array('USR_PASSWORD_HISTORY' => serialize(array(G::encryptOld($pwd))))); + + //change password + if ($changePassword === true) { + $user = new User(); + $currentUser = $user->changePassword($_SESSION['USER_LOGGED'], $_POST['form']['USR_PASSWORD']); + G::header('Location: ' . $currentUser["__REDIRECT_PATH__"]); + return; + } + + //Get the errors in the password $errorInPassword = $userProperty->validatePassword( $_POST['form']['USR_PASSWORD'], $userPropertyInfo['USR_LAST_UPDATE_DATE'], $userPropertyInfo['USR_LOGGED_NEXT_TIME'] ); - + //Get the policies enabled + $policiesInPassword = $userProperty->validatePassword('', date('Y-m-d'), $userPropertyInfo['USR_LOGGED_NEXT_TIME'], true); //Enable change password from GAP if (!isset($enableChangePasswordAfterNextLogin)) { $enableChangePasswordAfterNextLogin = true; @@ -333,24 +358,33 @@ try { define('NO_DISPLAY_USERNAME', 1); } //We will to get the message for the login - $messPassword = []; - $policySection = $userProperty->getMessageValidatePassword($errorInPassword, false); + $messPassword = $policySection = $userProperty->getMessageValidatePassword($policiesInPassword, false); $changePassword = ''; if (array_search('ID_PPP_CHANGE_PASSWORD_AFTER_NEXT_LOGIN', $errorInPassword)) { $changePassword .= G::LoadTranslation('ID_PPP_CHANGE_PASSWORD_AFTER_NEXT_LOGIN') . '

'; } - $messPassword['DESCRIPTION'] = $changePassword . $policySection['DESCRIPTION'] . '
'; + $messPassword['DESCRIPTION'] = $changePassword . $policySection['DESCRIPTION'] . ''; $G_PUBLISH = new Publisher; $version = explode('.', trim(file_get_contents(PATH_GULLIVER . 'VERSION'))); $version = isset($version[0]) ? intval($version[0]) : 0; + if ($version >= 3) { - $G_PUBLISH->AddContent('xmlform', 'xmlform', 'login/changePasswordpm3', '', $messPassword, - 'changePassword'); + $values = [ + "usrUsername" => $usr, + "usrPassword" => $pwd, + "userEnvironment" => config("system.workspace"), + "browserTimeZoneOffset" => $_POST['form']['BROWSER_TIME_ZONE_OFFSET'] + ]; + $messPassword['__USR_PASSWORD_CHANGE__'] = G::generateUniqueID(); + Cache::put($messPassword['__USR_PASSWORD_CHANGE__'], $values, 2); + $G_PUBLISH->AddContent('xmlform', 'xmlform', 'login/changePasswordpm3', '', $messPassword, 'sysLoginVerify'); + G::RenderPage('publish'); + session_destroy(); } else { $G_PUBLISH->AddContent('xmlform', 'xmlform', 'login/changePassword', '', $messPassword, 'changePassword'); + G::RenderPage('publish'); } - G::RenderPage('publish'); die; } diff --git a/workflow/engine/methods/login/changePassword.php b/workflow/engine/methods/login/changePassword.php index a17e2739d..43f55089b 100644 --- a/workflow/engine/methods/login/changePassword.php +++ b/workflow/engine/methods/login/changePassword.php @@ -1,92 +1,7 @@ load($_SESSION['USER_LOGGED']); -global $RBAC; -$aData['USR_UID'] = $aUser['USR_UID']; -$aData['USR_USERNAME'] = $aUser['USR_USERNAME']; -$aData['USR_PASSWORD'] = Bootstrap::hashPassword($_POST['form']['USR_PASSWORD']); -$aData['USR_FIRSTNAME'] = $aUser['USR_FIRSTNAME']; -$aData['USR_LASTNAME'] = $aUser['USR_LASTNAME']; -$aData['USR_EMAIL'] = $aUser['USR_EMAIL']; -$aData['USR_DUE_DATE'] = $aUser['USR_DUE_DATE']; -$aData['USR_UPDATE_DATE'] = date('Y-m-d H:i:s'); -$RBAC->updateUser($aData, $aUser['USR_ROLE']); -$aData['USR_COUNTRY'] = $aUser['USR_COUNTRY']; -$aData['USR_CITY'] = $aUser['USR_CITY']; -$aData['USR_LOCATION'] = $aUser['USR_LOCATION']; -$aData['USR_ADDRESS'] = $aUser['USR_ADDRESS']; -$aData['USR_PHONE'] = $aUser['USR_PHONE']; -$aData['USR_ZIP_CODE'] = $aUser['USR_ZIP_CODE']; -$aData['USR_POSITION'] = $aUser['USR_POSITION']; -$oUser->update($aData); -require_once 'classes/model/UsersProperties.php'; -$oUserProperty = new UsersProperties(); -$aUserProperty = $oUserProperty->load($_SESSION['USER_LOGGED']); -$aHistory = unserialize($aUserProperty['USR_PASSWORD_HISTORY']); - -if (!is_array($aHistory)) { - $aHistory = array(); -} - -if (!defined('PPP_PASSWORD_HISTORY')) { - define('PPP_PASSWORD_HISTORY', 0); -} - -if (PPP_PASSWORD_HISTORY > 0) { - if (count($aHistory) >= PPP_PASSWORD_HISTORY) { - array_shift($aHistory); - } - $aHistory[] = $_POST['form']['USR_PASSWORD']; -} - -$aUserProperty['USR_LAST_UPDATE_DATE'] = date('Y-m-d H:i:s'); -$aUserProperty['USR_LOGGED_NEXT_TIME'] = 0; -$aUserProperty['USR_PASSWORD_HISTORY'] = serialize($aHistory); -$oUserProperty->update($aUserProperty); - -if (class_exists('redirectDetail')) { - //falta validar... - if (isset($RBAC->aUserInfo['PROCESSMAKER']['ROLE']['ROL_CODE'])) { - $userRole = $RBAC->aUserInfo['PROCESSMAKER']['ROLE']['ROL_CODE']; - } - $oPluginRegistry = PluginRegistry::loadSingleton(); - //$oPluginRegistry->showArrays(); - $aRedirectLogin = $oPluginRegistry->getRedirectLogins(); - if (isset($aRedirectLogin)) { - if (is_array($aRedirectLogin)) { - /** @var \ProcessMaker\Plugins\Interfaces\RedirectDetail $detail */ - foreach ($aRedirectLogin as $detail) { - if (isset($detail->sPathMethod)) { - if ($detail->equalRoleCodeTo($userRole)) { - G::header( - 'location: /sys' . SYS_TEMP . '/' . SYS_LANG . - '/' . SYS_SKIN . '/' . $detail->getPathMethod() - ); - die; - } - } - } - } - } -} -//end plugin - -if (isset($frm['USER_LANG'])) { - if ($frm['USER_LANG'] != '') { - $lang = $frm['USER_LANG']; - } -} else { - if (defined('SYS_LANG')) { - $lang = SYS_LANG; - } else { - $lang = 'en'; - } -} -$sLocation = $oUserProperty->redirectTo($_SESSION['USER_LOGGED'], $lang); -G::header('Location: ' . $sLocation); -die; +use ProcessMaker\BusinessModel\User; +$user = new User(); +$currentUser = $user->changePassword($_SESSION['USER_LOGGED'], $_POST['form']['USR_PASSWORD'], isset($_POST['form']['USER_LANG']) ? $_POST['form']['USER_LANG'] : ""); +G::header('Location: ' . $currentUser["__REDIRECT_PATH__"]); diff --git a/workflow/engine/methods/login/retrivePassword.php b/workflow/engine/methods/login/retrivePassword.php index 1e0f9f806..4603bf840 100644 --- a/workflow/engine/methods/login/retrivePassword.php +++ b/workflow/engine/methods/login/retrivePassword.php @@ -68,7 +68,7 @@ if ($userExists === true && $userData['USR_EMAIL'] != '' && $userData['USR_EMAIL '', '', 0, - 'TEST', + WsBase::MESSAGE_TYPE_RETRIEVE_PASSWORD, $subject, $from, $data['USR_EMAIL'], diff --git a/workflow/engine/methods/mails/emailsAjax.php b/workflow/engine/methods/mails/emailsAjax.php index f8fb1adf3..d83cf5d07 100644 --- a/workflow/engine/methods/mails/emailsAjax.php +++ b/workflow/engine/methods/mails/emailsAjax.php @@ -2,6 +2,7 @@ use ProcessMaker\Plugins\PluginRegistry; use ProcessMaker\Exception\RBACException; +use ProcessMaker\Util\DateTime; $req = (isset($_REQUEST['request']) ? $_REQUEST['request'] : ''); @@ -130,8 +131,8 @@ switch ($req) { $tasTitleDefault = G::LoadTranslation('ID_TASK_NOT_RELATED'); while ($result->next()) { $row = $result->getRow(); - $row['APP_MSG_FROM'] = htmlentities($row['APP_MSG_FROM'], ENT_QUOTES, "UTF-8"); $row['APP_MSG_STATUS'] = ucfirst($row['APP_MSG_STATUS']); + $row['APP_MSG_DATE'] = DateTime::convertUtcToTimeZone($row['APP_MSG_DATE']); switch ($filterBy) { case 'CASES': diff --git a/workflow/engine/methods/processes/processes_Ajax.php b/workflow/engine/methods/processes/processes_Ajax.php index 6a978a941..fcca140b9 100644 --- a/workflow/engine/methods/processes/processes_Ajax.php +++ b/workflow/engine/methods/processes/processes_Ajax.php @@ -1,28 +1,22 @@ . - * - * For more information, contact Colosa Inc, 2566 Le Jeune Rd., - * Coral Gables, FL, 33134, USA, or email info@colosa.com. - */ try { + // Validate the access to the actions of this file + if (!empty($_REQUEST['action']) && $_REQUEST['action'] == 'load') { + // Validate if exists the session variable "PROCESS", this action is requested from case tracker and running cases + $cannotAccess = empty($_SESSION['PROCESS']); + } else { + // Validate PM_FACTORY permission + global $RBAC; + $cannotAccess = $RBAC->userCanAccess('PM_FACTORY') !== 1; + } + + if ($cannotAccess) { + G::SendTemporalMessage( 'ID_USER_HAVENT_RIGHTS_PAGE', 'error', 'labels' ); + G::header( 'Location: ../login/login' ); + die(); + } + $filter = new InputFilter(); $_GET = $filter->xssFilterHard($_GET); $_POST = $filter->xssFilterHard($_POST); @@ -693,41 +687,38 @@ try { $_REQUEST['filename'] = $filter->xssFilterHard($_REQUEST['filename']); global $G_PUBLISH; $G_PUBLISH = new Publisher(); - global $RBAC; - if ($RBAC->userCanAccess('PM_FACTORY') == 1) { - $app = new Processes(); - if (!$app->processExists($_REQUEST['pro_uid'])) { - echo G::LoadTranslation('ID_PROCESS_UID_NOT_DEFINED'); - die; - } - - $sDir = ""; - if (isset($_REQUEST['MAIN_DIRECTORY'])) { - $_REQUEST['MAIN_DIRECTORY'] = $filter->xssFilterHard($_REQUEST['MAIN_DIRECTORY']); - $sDir = $_REQUEST['MAIN_DIRECTORY']; - } - switch ($sDir) { - case 'mailTemplates': - $sDirectory = PATH_DATA_MAILTEMPLATES . $_REQUEST['pro_uid'] . PATH_SEP . $_REQUEST['filename']; - G::auditLog('ProcessFileManager', 'Save template (' . $_REQUEST['filename'] . ') in process "' . $resultProcess['PRO_TITLE'] . '"'); - break; - case 'public': - $sDirectory = PATH_DATA_PUBLIC . $_REQUEST['pro_uid'] . PATH_SEP . $_REQUEST['filename']; - G::auditLog('ProcessFileManager', 'Save public template (' . $_REQUEST['filename'] . ') in process "' . $resultProcess['PRO_TITLE'] . '"'); - break; - default: - $sDirectory = PATH_DATA_MAILTEMPLATES . $_REQUEST['pro_uid'] . PATH_SEP . $_REQUEST['filename']; - break; - } - $fp = fopen($sDirectory, 'w'); - $content = stripslashes($_REQUEST['fcontent']); - $content = str_replace("@amp@", "&", $content); - $content = base64_decode($content); - fwrite($fp, $content); - fclose($fp); - $sDirectory = $filter->xssFilterHard($sDirectory); - echo 'saved: ' . $sDirectory; + $app = new Processes(); + if (!$app->processExists($_REQUEST['pro_uid'])) { + echo G::LoadTranslation('ID_PROCESS_UID_NOT_DEFINED'); + die; } + + $sDir = ""; + if (isset($_REQUEST['MAIN_DIRECTORY'])) { + $_REQUEST['MAIN_DIRECTORY'] = $filter->xssFilterHard($_REQUEST['MAIN_DIRECTORY']); + $sDir = $_REQUEST['MAIN_DIRECTORY']; + } + switch ($sDir) { + case 'mailTemplates': + $sDirectory = PATH_DATA_MAILTEMPLATES . $_REQUEST['pro_uid'] . PATH_SEP . $_REQUEST['filename']; + G::auditLog('ProcessFileManager', 'Save template (' . $_REQUEST['filename'] . ') in process "' . $resultProcess['PRO_TITLE'] . '"'); + break; + case 'public': + $sDirectory = PATH_DATA_PUBLIC . $_REQUEST['pro_uid'] . PATH_SEP . $_REQUEST['filename']; + G::auditLog('ProcessFileManager', 'Save public template (' . $_REQUEST['filename'] . ') in process "' . $resultProcess['PRO_TITLE'] . '"'); + break; + default: + $sDirectory = PATH_DATA_MAILTEMPLATES . $_REQUEST['pro_uid'] . PATH_SEP . $_REQUEST['filename']; + break; + } + $fp = fopen($sDirectory, 'w'); + $content = stripslashes($_REQUEST['fcontent']); + $content = str_replace("@amp@", "&", $content); + $content = base64_decode($content); + fwrite($fp, $content); + fclose($fp); + $sDirectory = $filter->xssFilterHard($sDirectory); + echo 'saved: ' . $sDirectory; break; case 'getSessid': if (isset($_SESSION['USER_LOGGED'])) { diff --git a/workflow/engine/methods/processes/processes_GetFile.php b/workflow/engine/methods/processes/processes_GetFile.php index 685519820..df2e559c3 100644 --- a/workflow/engine/methods/processes/processes_GetFile.php +++ b/workflow/engine/methods/processes/processes_GetFile.php @@ -4,14 +4,11 @@ $RBAC->allows(basename(__FILE__), $_GET['MAIN_DIRECTORY']); $mainDirectory = !empty($_GET['MAIN_DIRECTORY']) ? $_GET['MAIN_DIRECTORY'] : ''; $proUid = !empty($_GET['PRO_UID']) ? $_GET['PRO_UID'] : ''; -$currentDirectory = !empty($_GET['CURRENT_DIRECTORY']) ? realpath($_GET['CURRENT_DIRECTORY']) . PATH_SEP : ''; -$file = !empty($_GET['FILE']) ? realpath($_GET['FILE']) : ''; +$currentDirectory = !empty($_GET['CURRENT_DIRECTORY']) ? $_GET['CURRENT_DIRECTORY'] . PATH_SEP : ''; +$file = !empty($_GET['FILE']) ? $_GET['FILE'] : ''; $extension = (!empty($_GET['sFilextension']) && $_GET['sFilextension'] === 'javascript') ? '.js' : ''; -//validated process exists, return throw if not exists. -$process = new Process(); -$process->load($proUid); - +// Validate the main directory switch ($mainDirectory) { case 'mailTemplates': $directory = PATH_DATA_MAILTEMPLATES; @@ -24,9 +21,20 @@ switch ($mainDirectory) { break; } +// Validate if process exists, an exception is throwed if not exists +$process = new Process(); +$process->load($proUid); + +// Validate directory and file requested +$filter = new InputFilter(); +$currentDirectory = $filter->validatePath($currentDirectory); +$file = $filter->validatePath($file); + +// Build requested path $directory .= $proUid . PATH_SEP . $currentDirectory; $file .= $extension; +// Stream the file if path exists if (file_exists($directory . $file)) { G::streamFile($directory . $file, true); } diff --git a/workflow/engine/methods/processes/processes_Import_Ajax.php b/workflow/engine/methods/processes/processes_Import_Ajax.php index 0f724bc58..8804289aa 100644 --- a/workflow/engine/methods/processes/processes_Import_Ajax.php +++ b/workflow/engine/methods/processes/processes_Import_Ajax.php @@ -25,7 +25,7 @@ use \ProcessMaker\Importer\XmlImporter; use ProcessMaker\Validation\ValidationUploadedFiles; -ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) { +ValidationUploadedFiles::getValidationUploadedFiles()->dispatch(function($validator) { echo G::json_encode([ 'status' => 'ERROR', 'success' => true, diff --git a/workflow/engine/methods/processes/processes_doUpload.php b/workflow/engine/methods/processes/processes_doUpload.php index db0077ef9..f8dc3b0d5 100644 --- a/workflow/engine/methods/processes/processes_doUpload.php +++ b/workflow/engine/methods/processes/processes_doUpload.php @@ -27,7 +27,7 @@ if ($RBAC->userCanAccess('PM_FACTORY') == 1) { } } - ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) { + ValidationUploadedFiles::getValidationUploadedFiles()->dispatch(function($validator) { $response = [ 'result' => 0, 'msg' => $validator->getMessage() diff --git a/workflow/engine/methods/services/ActionsByEmailDataFormPost.php b/workflow/engine/methods/services/ActionsByEmailDataFormPost.php index d06640ba5..32198a3d8 100644 --- a/workflow/engine/methods/services/ActionsByEmailDataFormPost.php +++ b/workflow/engine/methods/services/ActionsByEmailDataFormPost.php @@ -1,9 +1,30 @@ verifyfeature('zLhSk5TeEQrNFI2RXFEVktyUGpnczV1WEJNWVp6cjYxbTU3R29mVXVZNWhZQT0=')) { + + /** + * To do: The following evaluation must be moved after saving the data (so as not to lose the data entered in the form). + * It only remains because it is an old behavior, which must be defined by "Product Owner". + * @see workflow/engine/methods/cases/cases_SaveData.php + */ + $validator = ValidationUploadedFiles::getValidationUploadedFiles()->runRulesForFileEmpty(); + if ($validator->fails()) { + G::SendMessageText($validator->getMessage(), "ERROR"); + $url = explode("sys" . config("system.workspace"), $_SERVER['HTTP_REFERER']); + G::header("location: " . "/sys" . config("system.workspace") . $url[1]); + die(); + } + $G_PUBLISH = new Publisher(); try { @@ -61,7 +82,12 @@ if (PMLicensedFeatures::getSingleton() //Update case info $case->updateCase($appUid, $casesFields); - + if (isset($_FILES ['form'])) { + if (isset($_FILES["form"]["name"]) && count($_FILES["form"]["name"]) > 0) { + $oInputDocument = new InputDocument(); + $oInputDocument->uploadFileCase($_FILES, $case, $casesFields, $currentUsrUid, $appUid, $delIndex); + } + } $wsBaseInstance = new WsBase(); $result = $wsBaseInstance->derivateCase( $casesFields['CURRENT_USER_UID'], $appUid, $delIndex, true @@ -101,13 +127,6 @@ if (PMLicensedFeatures::getSingleton() $dataAbeRequests['ABE_REQ_ANSWERED'] = 1; $code == 0 ? uploadAbeRequest($dataAbeRequests) : ''; - if (isset($_FILES ['form'])) { - if (isset($_FILES["form"]["name"]) && count($_FILES["form"]["name"]) > 0) { - $oInputDocument = new \ProcessMaker\BusinessModel\Cases\InputDocument(); - $oInputDocument->uploadFileCase($_FILES, $case, $casesFields, $currentUsrUid, $appUid, $delIndex); - } - } - $assign = $result['message']; $aMessage['MESSAGE'] = '' . G::loadTranslation('ID_ABE_INFORMATION_SUBMITTED') . ''; } else { diff --git a/workflow/engine/methods/services/soap2.php b/workflow/engine/methods/services/soap2.php index 80c645310..83daf42ed 100644 --- a/workflow/engine/methods/services/soap2.php +++ b/workflow/engine/methods/services/soap2.php @@ -1,6 +1,7 @@ sessionId); @@ -392,7 +400,22 @@ function SendMessage($params) } $ws = new WsBase(); - $res = $ws->sendMessage($params->caseId, $params->from, $params->to, $params->cc, $params->bcc, $params->subject, $params->template); + $res = $ws->sendMessage( + $params->caseId, + $params->from, + $params->to, + $params->cc, + $params->bcc, + $params->subject, + $params->template, + null, + null, + true, + 0, + [], + 0, + WsBase::MESSAGE_TYPE_SOAP + ); return $res->getPayloadArray(); } @@ -923,6 +946,13 @@ function systemInformation($params) return $res; } +/** + * Obtains the cases notes in a soap call + * + * @param $params + * @return WsGetCaseNotesResponse|WsResponse + * + */ function getCaseNotes($params) { $vsResult = isValidSession($params->sessionId); @@ -934,6 +964,11 @@ function getCaseNotes($params) $ws = new WsBase(); $res = $ws->getCaseNotes($params->applicationID, $params->userUid); + foreach ($res->notes as $key => $value) { + $res->notes[$key]['note_date'] = DateTime::convertUtcToTimeZone($res->notes[$key]['note_date']); + + } + return $res; } diff --git a/workflow/engine/methods/setup/languages_Import.php b/workflow/engine/methods/setup/languages_Import.php index 1a1f3fa55..757a692f3 100644 --- a/workflow/engine/methods/setup/languages_Import.php +++ b/workflow/engine/methods/setup/languages_Import.php @@ -26,7 +26,7 @@ if ($access != 1) { $result = new stdClass(); try { - ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) { + ValidationUploadedFiles::getValidationUploadedFiles()->dispatch(function($validator) { throw new Exception($validator->getMessage()); }); //if the xmlform path is writeable diff --git a/workflow/engine/methods/setup/pluginsImportFile.php b/workflow/engine/methods/setup/pluginsImportFile.php index 8ddce45fa..79a051d5f 100644 --- a/workflow/engine/methods/setup/pluginsImportFile.php +++ b/workflow/engine/methods/setup/pluginsImportFile.php @@ -32,7 +32,7 @@ global $RBAC; $RBAC->requirePermissions('PM_SETUP_ADVANCE'); try { - ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) { + ValidationUploadedFiles::getValidationUploadedFiles()->dispatch(function($validator) { throw new Exception($validator->getMessage()); }); //load the variables diff --git a/workflow/engine/methods/setup/setupSchemas/triggerContentUpdate.sql b/workflow/engine/methods/setup/setupSchemas/triggerContentUpdate.sql index 2c1a28e6a..20844bf0d 100644 --- a/workflow/engine/methods/setup/setupSchemas/triggerContentUpdate.sql +++ b/workflow/engine/methods/setup/setupSchemas/triggerContentUpdate.sql @@ -3,7 +3,7 @@ CREATE TRIGGER CONTENT_UPDATE BEFORE UPDATE ON CONTENT FOR EACH ROW BEGIN - DECLARE str TEXT; + DECLARE str MEDIUMTEXT; IF (NEW.CON_VALUE IS NULL) THEN SET str = ''; diff --git a/workflow/engine/methods/setup/skin_Ajax.php b/workflow/engine/methods/setup/skin_Ajax.php index ad47b31bb..36486679e 100644 --- a/workflow/engine/methods/setup/skin_Ajax.php +++ b/workflow/engine/methods/setup/skin_Ajax.php @@ -200,7 +200,7 @@ function newSkin ($baseSkin = 'classic') function importSkin () { try { - ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) { + ValidationUploadedFiles::getValidationUploadedFiles()->dispatch(function($validator) { throw new Exception($validator->getMessage()); }); if (! isset( $_FILES['uploadedFile'] )) { diff --git a/workflow/engine/methods/users/users_Ajax.php b/workflow/engine/methods/users/users_Ajax.php index 86978577e..ff4aef854 100644 --- a/workflow/engine/methods/users/users_Ajax.php +++ b/workflow/engine/methods/users/users_Ajax.php @@ -149,6 +149,10 @@ try { $criteria->add(ProcessUserPeer::USR_UID, $usrUid, Criteria::EQUAL); $criteria->add(ProcessUserPeer::PU_TYPE, "SUPERVISOR", Criteria::EQUAL); ProcessUserPeer::doDelete($criteria); + //Destroy session after delete user + $RBAC->destroySessionUser($usrUid); + (new OauthClients())->removeByUser($usrUid); + G::auditLog("DeleteUser", "User Name: ". $userName." User ID: (".$usrUid.") "); break; case 'changeUserStatus': @@ -160,6 +164,8 @@ try { $userData = $userInstance->load($_REQUEST['USR_UID']); $userData['USR_STATUS'] = $_REQUEST['NEW_USR_STATUS']; $userInstance->update($userData); + //Destroy session after inactive user + $_REQUEST['NEW_USR_STATUS'] == 'INACTIVE' ? $RBAC->destroySessionUser($_REQUEST['USR_UID']) : null; $msg = $_REQUEST['NEW_USR_STATUS'] == 'ACTIVE'? "EnableUser" : "DisableUser"; G::auditLog($msg, "User Name: ".$userData['USR_USERNAME']." User ID: (".$userData['USR_UID'].") "); diff --git a/workflow/engine/skinEngine/base/css/pmos-xtheme-gray.css b/workflow/engine/skinEngine/base/css/pmos-xtheme-gray.css index 87b8593e3..22e902609 100644 --- a/workflow/engine/skinEngine/base/css/pmos-xtheme-gray.css +++ b/workflow/engine/skinEngine/base/css/pmos-xtheme-gray.css @@ -1603,3 +1603,73 @@ padding:3px 3px 3px 5px; white-space:normal; } + +.cancelSummary { + color: #333; + background: #fff; + border:1px #ccc solid; +} +.claimCaseSummary { + color: #ffffff; + background-color: #337ab7; + border:1px #2e6da4 solid; +} +.claimCaseSummary .x-btn-text { + color: #fff; + padding: 6px 6px 6px 6px; + height: 28px !important; + -moz-border-radius: 20px; + -webkit-border-radius: 20px; + border-radius: 20px; +} +.cancelSummary .x-btn-text { + padding: 6px 6px 6px 6px; + height: 25px !important; + -moz-border-radius: 20px; + -webkit-border-radius: 20px; + border-radius: 20px; +} +.claimCaseSummary td { + color: #ffffff; + background: #337ab7; + border-color: #2e6da4; +} +.claimCaseSummary tbody:hover td { + color: #ffffff; + background: #286090; + border-color: #204d74; +} +.cancelSummary td { + color: #333; + background: #fff; +} +.cancelSummary tbody:hover td { + color: #333333; + background: #e6e6e6; + border-color: #adadad; +} +.cancelSummary .claimCaseSummary { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-size: 12px !important; + font-weight: 400; + line-height: 1.42857143; + text-align: center; + white-space: nowrap; + vertical-align: middle; + -ms-touch-action: manipulation; + touch-action: manipulation; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.navPanelBottom .x-toolbar-cell { + clear: both; + height: 50px; +} \ No newline at end of file diff --git a/workflow/engine/skinEngine/neoclassic/css/pmos-xtheme-gray.css b/workflow/engine/skinEngine/neoclassic/css/pmos-xtheme-gray.css index 17b6db332..d450c5eb9 100644 --- a/workflow/engine/skinEngine/neoclassic/css/pmos-xtheme-gray.css +++ b/workflow/engine/skinEngine/neoclassic/css/pmos-xtheme-gray.css @@ -1795,3 +1795,73 @@ white-space:normal; -moz-border-radius: 5px; vertical-align: middle; } + +.cancelSummary { + color: #333; + background: #fff; + border:1px #ccc solid; +} +.claimCaseSummary { + color: #ffffff; + background-color: #337ab7; + border:1px #2e6da4 solid; +} +.claimCaseSummary .x-btn-text { + color: #fff; + padding: 6px 6px 6px 6px; + height: 28px !important; + -moz-border-radius: 20px; + -webkit-border-radius: 20px; + border-radius: 20px; +} +.cancelSummary .x-btn-text { + padding: 6px 6px 6px 6px; + height: 25px !important; + -moz-border-radius: 20px; + -webkit-border-radius: 20px; + border-radius: 20px; +} +.claimCaseSummary td { + color: #ffffff; + background-color: #337ab7; + border-color: #2e6da4; +} +.claimCaseSummary tbody:hover td { + color: #ffffff; + background-color: #286090; + border-color: #204d74; +} +.cancelSummary td { + color: #333; + background: #fff; +} +.cancelSummary tbody:hover td { + color: #333333; + background-color: #e6e6e6; + border-color: #adadad; +} +.cancelSummary .claimCaseSummary { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-size: 12px !important; + font-weight: 400; + line-height: 1.42857143; + text-align: center; + white-space: nowrap; + vertical-align: middle; + -ms-touch-action: manipulation; + touch-action: manipulation; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.navPanelBottom .x-toolbar-cell { + clear: both; + height: 50px; +} diff --git a/workflow/engine/skinEngine/uxmodern/css/pmos-xtheme-gray.css b/workflow/engine/skinEngine/uxmodern/css/pmos-xtheme-gray.css index ea0c5ab9a..61a38943a 100644 --- a/workflow/engine/skinEngine/uxmodern/css/pmos-xtheme-gray.css +++ b/workflow/engine/skinEngine/uxmodern/css/pmos-xtheme-gray.css @@ -1631,3 +1631,74 @@ td.x-cnotes-label { color:#848484; text-decoration: none; } + + +.cancelSummary { + color: #333; + background: #fff; + border:1px #ccc solid; +} +.claimCaseSummary { + color: #ffffff; + background-color: #337ab7; + border:1px #2e6da4 solid; +} +.claimCaseSummary .x-btn-text { + color: #fff; + padding: 6px 6px 6px 6px; + height: 28px !important; + -moz-border-radius: 20px; + -webkit-border-radius: 20px; + border-radius: 20px; +} +.cancelSummary .x-btn-text { + padding: 6px 6px 6px 6px; + height: 25px !important; + -moz-border-radius: 20px; + -webkit-border-radius: 20px; + border-radius: 20px; +} +.claimCaseSummary td { + color: #ffffff; + background: #337ab7; + border-color: #2e6da4; +} +.claimCaseSummary tbody:hover td { + color: #ffffff; + background: #286090; + border-color: #204d74; +} +.cancelSummary td { + color: #333; + background: #fff; +} +.cancelSummary tbody:hover td { + color: #333333; + background: #e6e6e6; + border-color: #adadad; +} +.cancelSummary .claimCaseSummary { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-size: 12px !important; + font-weight: 400; + line-height: 1.42857143; + text-align: center; + white-space: nowrap; + vertical-align: middle; + -ms-touch-action: manipulation; + touch-action: manipulation; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.navPanelBottom .x-toolbar-cell { + clear: both; + height: 50px; +} \ No newline at end of file diff --git a/workflow/engine/skinEngine/uxs/css/pmos-xtheme-gray.css b/workflow/engine/skinEngine/uxs/css/pmos-xtheme-gray.css index a3ec295bd..806279eae 100644 --- a/workflow/engine/skinEngine/uxs/css/pmos-xtheme-gray.css +++ b/workflow/engine/skinEngine/uxs/css/pmos-xtheme-gray.css @@ -1176,3 +1176,74 @@ td.x-cnotes-label { font: 11px arial,tahoma,helvetica,sans-serif; color: #465070; } + + +.cancelSummary { + color: #333; + background: #fff; + border:1px #ccc solid; +} +.claimCaseSummary { + color: #ffffff; + background-color: #337ab7; + border:1px #2e6da4 solid; +} +.claimCaseSummary .x-btn-text { + color: #fff; + padding: 6px 6px 6px 6px; + height: 28px !important; + -moz-border-radius: 20px; + -webkit-border-radius: 20px; + border-radius: 20px; +} +.cancelSummary .x-btn-text { + padding: 6px 6px 6px 6px; + height: 25px !important; + -moz-border-radius: 20px; + -webkit-border-radius: 20px; + border-radius: 20px; +} +.claimCaseSummary td { + color: #ffffff; + background: #337ab7; + border-color: #2e6da4; +} +.claimCaseSummary tbody:hover td { + color: #ffffff; + background: #286090; + border-color: #204d74; +} +.cancelSummary td { + color: #333; + background: #fff; +} +.cancelSummary tbody:hover td { + color: #333333; + background: #e6e6e6; + border-color: #adadad; +} +.cancelSummary .claimCaseSummary { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-size: 12px !important; + font-weight: 400; + line-height: 1.42857143; + text-align: center; + white-space: nowrap; + vertical-align: middle; + -ms-touch-action: manipulation; + touch-action: manipulation; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.navPanelBottom .x-toolbar-cell { + clear: both; + height: 50px; +} \ No newline at end of file diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/ActionsByEmail.php b/workflow/engine/src/ProcessMaker/BusinessModel/ActionsByEmail.php index 968335963..bdd47c37d 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/ActionsByEmail.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/ActionsByEmail.php @@ -4,30 +4,27 @@ namespace ProcessMaker\BusinessModel; use AbeConfiguration; use AbeConfigurationPeer; -use AppMessage; use AbeRequests; use AbeRequestsPeer; use AbeResponsesPeer; -use ApplicationPeer; use AppDelegation; use AppDelegationPeer; +use AppMessage; use Criteria; +use DynaformPeer; use EmailServerPeer; use Exception; use G; -use Publisher; -use ProcessMaker\BusinessModel\EmailServer; -use ProcessMaker\Core\System; -use ProcessMaker\Plugins\PluginRegistry; use PmDynaform; use PMLicensedFeatures; -use ProcessPeer; +use ProcessMaker\Core\System; +use ProcessMaker\Plugins\PluginRegistry; +use Publisher; use ResultSet; use SpoolRun; -use Users as ClassUsers; use stdClass; -use UsersPeer; -use TaskPeer; +use Users as ClassUsers; +use WsBase; /** * Description of ActionsByEmailService @@ -269,12 +266,15 @@ class ActionsByEmail } /** - * Get the information for the log - * + * Get the information for the log. + * * @param array $arrayData - * * @return array - */ + * + * @see ProcessMaker\Services\Api\ActionsByEmail->loadActionByEmail() + * @see workflow/engine/methods/actionsByEmail/actionsByEmailAjax.php + * @link https://wiki.processmaker.com/3.3/Actions_by_Email + */ public function loadActionByEmail(array $arrayData) { //Get the total @@ -335,10 +335,15 @@ class ActionsByEmail //Get the previous user $appDelegation = new AppDelegation(); $usrUid = $appDelegation->getUserAssignedInThread($data[$index]['APP_UID'], $data[$index]['DEL_PREVIOUS']); - $users = new ClassUsers(); - $dataRes = $users->load($usrUid); - if (!empty($dataRes)) { - $data[$index]['USER'] = $dataRes['USR_FIRSTNAME'] . ' ' . $dataRes['USR_LASTNAME']; + //This value can be empty when the previous task is: 'Script Task', 'Timer Event' or other without user. + if (!empty($usrUid)) { + $users = new ClassUsers(); + $dataRes = $users->load($usrUid); + if (!empty($dataRes)) { + $data[$index]['USER'] = $dataRes['USR_FIRSTNAME'] . ' ' . $dataRes['USR_LASTNAME']; + } else { + $data[$index]['USER'] = ''; + } } else { $data[$index]['USER'] = ''; } @@ -362,6 +367,9 @@ class ActionsByEmail * * @return string $message * @throws Exception + * + * @see workflow/engine/methods/actionsByEmail/actionsByEmailAjax.php + * @see \ProcessMaker\Services\Api\ActionsByEmail::forwardMail() */ public function forwardMail(array $arrayData) { @@ -393,7 +401,7 @@ class ActionsByEmail '', $dataRes['APP_UID'], $dataRes['DEL_INDEX'], - 'TEST', + WsBase::MESSAGE_TYPE_ACTIONS_BY_EMAIL, $dataRes['ABE_REQ_SUBJECT'], $aSetup['MESS_ACCOUNT'], $dataRes['ABE_REQ_SENT_TO'], @@ -403,7 +411,7 @@ class ActionsByEmail '', '', 'pending', - '', + 1, '', false, isset($dataRes['APP_NUMBER']) ? $dataRes['APP_NUMBER'] : 0, @@ -439,10 +447,14 @@ class ActionsByEmail } /** - * Get the decision from Actions By Email and check if is Bpmn Process + * Get the decision from Actions By Email and check if is Bpmn Process. * @param array $arrayData * * @return string $message + * + * @see workflow/engine/methods/actionsByEmail/actionsByEmailAjax.php + * @see ProcessMaker\Services\Api\ActionsByEmail->viewForm() + * @link https://wiki.processmaker.com/3.3/Actions_by_Email#Actions_by_Email_Log */ public function viewForm(array $arrayData) { @@ -457,6 +469,7 @@ class ActionsByEmail $criteria->addSelectColumn(AbeConfigurationPeer::TAS_UID); $criteria->addSelectColumn(AbeConfigurationPeer::DYN_UID); $criteria->addSelectColumn(AbeConfigurationPeer::ABE_ACTION_FIELD); + $criteria->addSelectColumn(AbeConfigurationPeer::ABE_TYPE); $criteria->addSelectColumn(AbeRequestsPeer::ABE_REQ_UID); $criteria->addSelectColumn(AbeRequestsPeer::APP_UID); @@ -472,17 +485,21 @@ class ActionsByEmail $resultRes->setFetchmode(ResultSet::FETCHMODE_ASSOC); $resultRes->next(); - $dataRes = Array(); + $dataRes = []; $message = G::LoadTranslation('ID_USER_NOT_RESPONDED_REQUEST'); if ($dataRes = $resultRes->getRow()) { $_SESSION['CURRENT_DYN_UID'] = trim($dataRes['DYN_UID']); $process = new \Process(); $isBpmn = $process->isBpmnProcess($dataRes['PRO_UID']); - if($isBpmn) { - $message = $this->viewFormBpmn($dataRes); + if ($isBpmn) { + if ($dataRes['ABE_TYPE'] === 'FIELD') { + $message = $this->viewFormBpmn($dataRes); + } else { + $message = G::LoadTranslation('ID_CASE_RESPONSE_NOT_AVAILABLE'); + } } else { - $message = $this->viewFormClassic($dataRes); + $message = $this->viewFormClassic($dataRes); //to do, review this function } } @@ -542,49 +559,57 @@ class ActionsByEmail } /** - * Get the decision from Actions By Email by BPMN dynaform - * @param array $arrayData - * - * @return string $message + * Get the decision from Actions By Email by BPMN dynaform. + * + * @param array $dataRes + * @return string + * + * @see ActionsByEmail->viewForm() + * @link https://wiki.processmaker.com/3.3/Actions_by_Email */ public function viewFormBpmn(array $dataRes) { - $_SESSION['CURRENT_DYN_UID'] = trim($dataRes['DYN_UID']); - $configuration['DYN_UID'] = trim($dataRes['DYN_UID']); + $_SESSION['CURRENT_DYN_UID'] = trim($dataRes['DYN_UID']); + $configuration['DYN_UID'] = trim($dataRes['DYN_UID']); $configuration['CURRENT_DYNAFORM'] = trim($dataRes['DYN_UID']); - $configuration['PRO_UID'] = trim($dataRes['PRO_UID']); + $configuration['PRO_UID'] = trim($dataRes['PRO_UID']); $criteriaD = new Criteria(); - $criteriaD->addSelectColumn(\DynaformPeer::DYN_CONTENT); - $criteriaD->addSelectColumn(\DynaformPeer::PRO_UID); - $criteriaD->add(\DynaformPeer::DYN_UID, trim($dataRes['DYN_UID'])); - $resultD = \DynaformPeer::doSelectRS($criteriaD); + $criteriaD->addSelectColumn(DynaformPeer::DYN_CONTENT); + $criteriaD->addSelectColumn(DynaformPeer::PRO_UID); + $criteriaD->add(DynaformPeer::DYN_UID, trim($dataRes['DYN_UID'])); + $resultD = DynaformPeer::doSelectRS($criteriaD); $resultD->setFetchmode(ResultSet::FETCHMODE_ASSOC); $resultD->next(); $configuration = $resultD->getRow(); - $field = new \stdClass(); + $field = new stdClass(); + $field->type = ''; + $field->label = ''; + $field->options = []; + $obj = new PmDynaform($configuration); + $message = G::LoadTranslation('ID_CASE_RESPONSE_NOT_AVAILABLE'); if ($dataRes['ABE_RES_DATA'] !== '') { - $value = unserialize($dataRes['ABE_RES_DATA']); - $actionField = str_replace(array('@@','@#','@=','@%','@?','@$'), '', $dataRes['ABE_ACTION_FIELD']); - $variables = G::json_decode($configuration['DYN_CONTENT'], true); + $value = unserialize($dataRes['ABE_RES_DATA']); + $actionField = str_replace(['@@', '@#', '@=', '@%', '@?', '@$'], '', $dataRes['ABE_ACTION_FIELD']); + $variables = G::json_decode($configuration['DYN_CONTENT'], true); if (is_array($value)) { - if(isset($variables['items'][0]['items'])) { + if (isset($variables['items'][0]['items'])) { $fields = $variables['items'][0]['items']; } } else { - if(isset($variables['items'][0]['items'])) { + if (isset($variables['items'][0]['items'])) { $fields = $variables['items'][0]['items']; foreach ($fields as $key => $row) { - foreach($row as $var) { - if(isset($var['variable'])) { + foreach ($row as $var) { + if (isset($var['variable'])) { if ($var['variable'] === $actionField) { $field->label = isset($var['label']) ? $var['label'] : ''; - $field->type = isset($var['type']) ? $var['type'] : ''; + $field->type = isset($var['type']) ? $var['type'] : ''; $values = $var['options']; - foreach ($values as $val){ + foreach ($values as $val) { $field->options[$val['value']] = $val['value']; } } @@ -592,28 +617,39 @@ class ActionsByEmail } } } - $message = ''; + switch ($field->type) { case 'dropdown': case 'radiogroup': case 'radio': - $message .= $field->label . ': '; - $message .= $field->options[$value]; + if (!empty($field->options[$value])) { + $message = $field->label . ': '; + $message .= $field->options[$value]; + } break; + /** + * 'yesno' is deprecated in version ProcessMaker 3.x.x. + * @deprecated + */ case 'yesno': - $message .= $field->label . ': '; - $message .= ($value == 1) ? G::loadTranslation('ID_YES') : G::loadTranslation('ID_NO'); + $message = $field->label . ': '; + $message .= $value == 1 ? G::LoadTranslation('ID_YES') : G::LoadTranslation('ID_NO'); break; case 'checkgroup': case 'checkbox': - $message .= $field->label . ': '; - $message .= ($value == 'On') ? G::loadTranslation('ID_CHECK') : G::loadTranslation('ID_UNCHECK'); + $message = $field->label . ': '; + if (!empty($value)) { + /** + * Value 'On' is deprecated in version ProcessMaker 3.x.x. + * now return '1'. + * @deprecated + */ + $message .= ($value == 'On' || $value == '1') ? G::LoadTranslation('ID_CHECK') : G::LoadTranslation('ID_UNCHECK'); + } break; } } } - - //Return return $message; } diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php index 2c73dff0d..d0aa34cb7 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php @@ -21,6 +21,7 @@ use BpmnEngineServicesSearchIndex; use Cases as ClassesCases; use CasesPeer; use Configurations; +use CreoleTypes; use Criteria; use DBAdapter; use EntitySolrRequestData; @@ -32,6 +33,7 @@ use InputDocument; use InvalidIndexSearchTextException; use ListParticipatedLast; use PmDynaform; +use PmTable; use ProcessMaker\BusinessModel\ProcessSupervisor as BmProcessSupervisor; use ProcessMaker\BusinessModel\Task as BmTask; use ProcessMaker\BusinessModel\User as BmUser; @@ -39,16 +41,16 @@ use ProcessMaker\Core\System; use ProcessMaker\Exception\UploadException; use ProcessMaker\Plugins\PluginRegistry; use ProcessMaker\Services\OAuth2\Server; +use ProcessMaker\Util\DateTime as UtilDateTime; use ProcessMaker\Validation\ExceptionRestApi; use ProcessMaker\Validation\Validator as FileValidator; + use ProcessPeer; use ProcessUser; use ProcessUserPeer; use RBAC; use ResultSet; -use RoutePeer; use SubApplication; -use SubProcessPeer; use Task as ModelTask; use TaskPeer; use Tasks as ClassesTasks; @@ -61,6 +63,8 @@ class Cases { private $formatFieldNameInUppercase = true; private $messageResponse = []; + private $solr = null; + private $solrEnv = null; const MB_IN_KB = 1024; const UNIT_MB = 'MB'; @@ -237,26 +241,11 @@ class Cases public function getListCounters($userUid, array $arrayType) { try { - $solrEnabled = false; - $solrConf = System::solrEnv(); - - if ($solrConf !== false) { - $ApplicationSolrIndex = new AppSolr( - $solrConf['solr_enabled'], - $solrConf['solr_host'], - $solrConf['solr_instance'] - ); - - if ($ApplicationSolrIndex->isSolrEnabled() && $solrConf['solr_enabled'] == true) { - $solrEnabled = true; - } - } - $appCacheView = new AppCacheView(); - if ($solrEnabled) { + if ($this->isSolrEnabled()) { $arrayListCounter = array_merge( - $ApplicationSolrIndex->getCasesCount($userUid), + $this->solr->getCasesCount($userUid), $appCacheView->getAllCounters(['completed', 'cancelled'], $userUid) ); } else { @@ -422,6 +411,28 @@ class Cases return $response; } + /** + * Verify if Solr is Enabled + * + * @return bool + */ + private function isSolrEnabled() + { + $solrEnabled = false; + $this->solrEnv = !empty($this->solrEnv) ? $this->solrEnv : System::solrEnv(); + if ($this->solrEnv !== false) { + $this->solr = !empty($this->solr) ? $this->solr : new AppSolr( + $this->solrEnv['solr_enabled'], + $this->solrEnv['solr_host'], + $this->solrEnv['solr_instance'] + ); + if ($this->solr->isSolrEnabled() && $this->solrEnv["solr_enabled"] == true) { + $solrEnabled = true; + } + } + return $solrEnabled; + } + /** * Get data of a Case * @@ -434,21 +445,11 @@ class Cases public function getCaseInfo($applicationUid, $userUid) { try { - $solrEnabled = 0; - if (($solrEnv = System::solrEnv()) !== false) { - $appSolr = new AppSolr( - $solrEnv["solr_enabled"], - $solrEnv["solr_host"], - $solrEnv["solr_instance"] - ); - if ($appSolr->isSolrEnabled() && $solrEnv["solr_enabled"] == true) { - //Check if there are missing records to reindex and reindex them - $appSolr->synchronizePendingApplications(); - $solrEnabled = 1; - } - } - if ($solrEnabled == 1) { + if ($this->isSolrEnabled()) { try { + //Check if there are missing records to reindex and reindex them + $this->solr->synchronizePendingApplications(); + $arrayData = array(); $delegationIndexes = array(); $columsToInclude = array("APP_UID"); @@ -464,7 +465,7 @@ class Cases $columsToIncludeFinal = array_merge($columsToInclude, $delegationIndexes); $solrRequestData = EntitySolrRequestData::createForRequestPagination( array( - "workspace" => $solrEnv["solr_instance"], + "workspace" => $this->solrEnv["solr_instance"], "startAfter" => 0, "pageSize" => 1000, "searchText" => $solrSearchText, @@ -476,7 +477,7 @@ class Cases ) ); //Use search index to return list of cases - $searchIndex = new BpmnEngineServicesSearchIndex($appSolr->isSolrEnabled(), $solrEnv["solr_host"]); + $searchIndex = new BpmnEngineServicesSearchIndex($this->solr->isSolrEnabled(), $this->solrEnv["solr_host"]); //Execute query $solrQueryResult = $searchIndex->getDataTablePaginatedList($solrRequestData); //Get the missing data from database @@ -484,7 +485,7 @@ class Cases foreach ($solrQueryResult->aaData as $i => $data) { $arrayApplicationUid[] = $data["APP_UID"]; } - $aaappsDBData = $appSolr->getListApplicationDelegationData($arrayApplicationUid); + $aaappsDBData = $this->solr->getListApplicationDelegationData($arrayApplicationUid); foreach ($solrQueryResult->aaData as $i => $data) { //Initialize array $delIndexes = array(); //Store all the delegation indexes @@ -513,7 +514,7 @@ class Cases $aRow["APP_UID"] = $data["APP_UID"]; //Get delegation data from DB //Filter data from db - $indexes = $appSolr->aaSearchRecords($aaappsDBData, array( + $indexes = $this->solr->aaSearchRecords($aaappsDBData, array( "APP_UID" => $applicationUid, "DEL_INDEX" => $delIndex )); @@ -662,6 +663,31 @@ class Cases } } + /** + * Get data of a sub-process case + * + * @param string $applicationUid Unique Case Id + * @param string $userUid Unique User Id + * + * @return array Return an array with information of Cases + * @throws Exception + */ + public function getCaseInfoSubProcess($applicationUid, $userUid) + { + + try { + $response = []; + $subApplication = new SubApplication(); + $data = $subApplication->loadByAppUidParent($applicationUid); + foreach ($data as $item) { + $response[] = $this->getCaseInfo($item['APP_UID'], $userUid); + } + return $response; + } catch (Exception $e) { + throw $e; + } + } + /** * Get data Task Case * @@ -2104,6 +2130,11 @@ class Cases * * @param string $applicationUid Unique id of Case * + * @see workflow/engine/src/ProcessMaker/Services/Api/Cases.php + * @see workflow/engine/src/ProcessMaker/Services/Api/Light.php + * + * @link https://wiki.processmaker.com/3.3/REST_API_Cases/Cases#Get_Case.27s_Tasks:_GET_.2Fcases.2F.7Bapp_uid.7D.2Ftasks + * * @return array Return an array with all Tasks of Case * @throws Exception */ @@ -2127,33 +2158,20 @@ class Cases $taskUid = ""; - //Get data - //SQL - $delimiter = DBAdapter::getStringDelimiter(); + //Obtain the list of tasks and their respectives users assigned to each one for an specific case + $case = new ClassesCases(); + $rsTasks = $case->getTasksInfoForACase($applicationUid, $processUid); - $criteria = new Criteria("workflow"); + while ($rsTasks->next()) { + $row = $rsTasks->getRow(); - $criteria->addSelectColumn(TaskPeer::TAS_UID); - $criteria->addSelectColumn(TaskPeer::TAS_TITLE); - $criteria->addSelectColumn(TaskPeer::TAS_DESCRIPTION); - $criteria->addSelectColumn(TaskPeer::TAS_START); - $criteria->addSelectColumn(TaskPeer::TAS_TYPE); - $criteria->addSelectColumn(TaskPeer::TAS_DERIVATION); - $criteria->addSelectColumn(TaskPeer::TAS_ASSIGN_TYPE); - $criteria->addSelectColumn(UsersPeer::USR_UID); - $criteria->addSelectColumn(UsersPeer::USR_USERNAME); - $criteria->addSelectColumn(UsersPeer::USR_FIRSTNAME); - $criteria->addSelectColumn(UsersPeer::USR_LASTNAME); - - $criteria->addJoin(TaskPeer::TAS_LAST_ASSIGNED, UsersPeer::USR_UID, Criteria::LEFT_JOIN); - - $criteria->add(TaskPeer::PRO_UID, $processUid, Criteria::EQUAL); - - $rsCriteria = TaskPeer::doSelectRS($criteria); - $rsCriteria->setFetchmode(ResultSet::FETCHMODE_ASSOC); - - while ($rsCriteria->next()) { - $row = $rsCriteria->getRow(); + //If the task is a multiple task + if ($row["TAS_ASSIGN_TYPE"] == 'MULTIPLE_INSTANCE' || $row["TAS_ASSIGN_TYPE"] == 'MULTIPLE_INSTANCE_VALUE_BASED') { + $row["USR_UID"] = ""; + $row["USR_USERNAME"] = ""; + $row["USR_FIRSTNAME"] = ""; + $row["USR_LASTNAME"] = ""; + } //Task if ($row["TAS_TYPE"] == "NORMAL") { @@ -2165,17 +2183,9 @@ class Cases $row["TAS_TITLE"] = $task->getTasTitle(); } } else { - $criteria2 = new Criteria("workflow"); - $criteria2->addSelectColumn(SubProcessPeer::PRO_UID); - $criteria2->addSelectColumn(TaskPeer::TAS_TITLE); - $criteria2->addSelectColumn(TaskPeer::TAS_DESCRIPTION); - $criteria2->addJoin(SubProcessPeer::TAS_PARENT, TaskPeer::TAS_UID, Criteria::LEFT_JOIN); - $criteria2->add(SubProcessPeer::PRO_PARENT, $processUid); - $criteria2->add(SubProcessPeer::TAS_PARENT, $row["TAS_UID"]); - - $rsCriteria2 = SubProcessPeer::doSelectRS($criteria2); - $rsCriteria2->setFetchmode(ResultSet::FETCHMODE_ASSOC); + //Get the task information when the task type is different from normal + $rsCriteria2 = $case->getTaskInfoForSubProcess($processUid, $row["TAS_UID"]); $rsCriteria2->next(); @@ -2191,18 +2201,8 @@ class Cases $routeType = ""; $arrayRoute = array(); - $criteria2 = new Criteria("workflow"); - - $criteria2->addAsColumn("ROU_NUMBER", RoutePeer::ROU_CASE); - $criteria2->addSelectColumn(RoutePeer::ROU_TYPE); - $criteria2->addSelectColumn(RoutePeer::ROU_CONDITION); - $criteria2->addAsColumn("TAS_UID", RoutePeer::ROU_NEXT_TASK); - $criteria2->add(RoutePeer::PRO_UID, $processUid, Criteria::EQUAL); - $criteria2->add(RoutePeer::TAS_UID, $row["TAS_UID"], Criteria::EQUAL); - $criteria2->addAscendingOrderByColumn("ROU_NUMBER"); - - $rsCriteria2 = RoutePeer::doSelectRS($criteria2); - $rsCriteria2->setFetchmode(ResultSet::FETCHMODE_ASSOC); + //Get the routes of a task + $rsCriteria2 = $case->getTaskRoutes($processUid, $row["TAS_UID"]); while ($rsCriteria2->next()) { $row2 = $rsCriteria2->getRow(); @@ -2219,25 +2219,7 @@ class Cases //Delegations $arrayAppDelegation = array(); - $criteria2 = new Criteria("workflow"); - - $criteria2->addSelectColumn(AppDelegationPeer::DEL_INDEX); - $criteria2->addSelectColumn(AppDelegationPeer::DEL_INIT_DATE); - $criteria2->addSelectColumn(AppDelegationPeer::DEL_TASK_DUE_DATE); - $criteria2->addSelectColumn(AppDelegationPeer::DEL_FINISH_DATE); - $criteria2->addSelectColumn(UsersPeer::USR_UID); - $criteria2->addSelectColumn(UsersPeer::USR_USERNAME); - $criteria2->addSelectColumn(UsersPeer::USR_FIRSTNAME); - $criteria2->addSelectColumn(UsersPeer::USR_LASTNAME); - - $criteria2->addJoin(AppDelegationPeer::USR_UID, UsersPeer::USR_UID, Criteria::LEFT_JOIN); - - $criteria2->add(AppDelegationPeer::APP_UID, $applicationUid, Criteria::EQUAL); - $criteria2->add(AppDelegationPeer::TAS_UID, $row["TAS_UID"], Criteria::EQUAL); - $criteria2->addAscendingOrderByColumn(AppDelegationPeer::DEL_INDEX); - - $rsCriteria2 = AppDelegationPeer::doSelectRS($criteria2); - $rsCriteria2->setFetchmode(ResultSet::FETCHMODE_ASSOC); + $rsCriteria2 = $case->getCaseDelegations($applicationUid, $row["TAS_UID"]); while ($rsCriteria2->next()) { $row2 = $rsCriteria2->getRow(); @@ -2268,8 +2250,10 @@ class Cases $appDelegationDuration = G::LoadTranslation("ID_NOT_FINISHED"); - if (!empty($row2["DEL_FINISH_DATE"]) && !empty($row2["DEL_INIT_DATE"])) { - $t = strtotime($row2["DEL_FINISH_DATE"]) - strtotime($row2["DEL_INIT_DATE"]); + $date = empty($row2["DEL_INIT_DATE"]) ? $row2["DEL_DELEGATE_DATE"] : $row2["DEL_INIT_DATE"]; + + if (!empty($row2["DEL_FINISH_DATE"]) && !empty($date)) { + $t = strtotime($row2["DEL_FINISH_DATE"]) - strtotime($date); $h = $t * (1 / 60) * (1 / 60); $m = ($h - (int)($h)) * (60 / 1); @@ -2290,40 +2274,22 @@ class Cases $this->getFieldNameByFormatFieldName("DEL_FINISH_DATE") => $arrayAppDelegationDate["DEL_FINISH_DATE"]["dateFormated"], $this->getFieldNameByFormatFieldName("DEL_DURATION") => $appDelegationDuration, $this->getFieldNameByFormatFieldName("USR_UID") => $row2["USR_UID"], - $this->getFieldNameByFormatFieldName("USR_USERNAME") => $row2["USR_USERNAME"] . "", - $this->getFieldNameByFormatFieldName("USR_FIRSTNAME") => $row2["USR_FIRSTNAME"] . "", - $this->getFieldNameByFormatFieldName("USR_LASTNAME") => $row2["USR_LASTNAME"] . "" + $this->getFieldNameByFormatFieldName("USR_USERNAME") => $row2["USR_USERNAME"], + $this->getFieldNameByFormatFieldName("USR_FIRSTNAME") => $row2["USR_FIRSTNAME"], + $this->getFieldNameByFormatFieldName("USR_LASTNAME") => $row2["USR_LASTNAME"] ); } //Status $status = ""; - //$criteria2 - $criteria2 = new Criteria("workflow"); - - $criteria2->addAsColumn("CANT", "COUNT(" . AppDelegationPeer::APP_UID . ")"); - $criteria2->addAsColumn("FINISH", "MIN(" . AppDelegationPeer::DEL_FINISH_DATE . ")"); - $criteria2->add(AppDelegationPeer::APP_UID, $applicationUid, Criteria::EQUAL); - $criteria2->add(AppDelegationPeer::TAS_UID, $row["TAS_UID"], Criteria::EQUAL); - - $rsCriteria2 = AppDelegationPeer::doSelectRS($criteria2); - $rsCriteria2->setFetchmode(ResultSet::FETCHMODE_ASSOC); + $rsCriteria2 = $case->getTotalAndMinDateForACase($applicationUid, $row["TAS_UID"]); $rsCriteria2->next(); $row2 = $rsCriteria2->getRow(); - //$criteria3 - $criteria3 = new Criteria("workflow"); - - $criteria3->addSelectColumn(AppDelegationPeer::DEL_FINISH_DATE); - $criteria3->add(AppDelegationPeer::APP_UID, $applicationUid, Criteria::EQUAL); - $criteria3->add(AppDelegationPeer::TAS_UID, $row["TAS_UID"], Criteria::EQUAL); - $criteria3->add(AppDelegationPeer::DEL_FINISH_DATE, null, Criteria::ISNULL); - - $rsCriteria3 = AppDelegationPeer::doSelectRS($criteria3); - $rsCriteria3->setFetchmode(ResultSet::FETCHMODE_ASSOC); + $rsCriteria3 = $case->getDelegationFinishDate($applicationUid, $row["TAS_UID"]); $rsCriteria3->next(); @@ -3538,7 +3504,7 @@ class Cases * @param string $listPeer , name of the list class * @param string $search , the parameter for search in the table * @param string $additionalClassName , name of the className of pmtable - * @param array $additionalColumns , columns related to the custom cases list + * @param array $additionalColumns , columns related to the custom cases list ex: TABLE_NAME.COLUMN_NAME * * @throws PropelException */ @@ -3547,31 +3513,35 @@ class Cases $listPeer, $search, $additionalClassName = '', - $additionalColumns = array() + $additionalColumns = [] ) { - $oTmpCriteria = ''; + $tmpCriteria = ''; //If we have additional tables configured in the custom cases list, prepare the variables for search if (count($additionalColumns) > 0) { require_once(PATH_DATA_SITE . 'classes' . PATH_SEP . $additionalClassName . '.php'); - $oNewCriteria = new Criteria("workflow"); - $oTmpCriteria = $oNewCriteria->getNewCriterion(current($additionalColumns), "%" . $search . "%", - Criteria::LIKE); + + $columnPivot = current($additionalColumns); + $tableAndColumn = explode(".", $columnPivot); + $type = PmTable::getTypeOfColumn($listPeer, $tableAndColumn[0], $tableAndColumn[1]); + $tmpCriteria = $this->defineCriteriaByColumnType($type, $columnPivot, $search); //We prepare the query related to the custom cases list - foreach (array_slice($additionalColumns, 1) as $value) { - $oTmpCriteria = $oNewCriteria->getNewCriterion($value, "%" . $search . "%", - Criteria::LIKE)->addOr($oTmpCriteria); + foreach (array_slice($additionalColumns, 1) as $column) { + $tableAndColumn = explode(".", $column); + $type = PmTable::getTypeOfColumn($listPeer, $tableAndColumn[0], $tableAndColumn[1]); + $tmpCriteria = $this->defineCriteriaByColumnType($type, $column, $search)->addOr($tmpCriteria); + } } - if (!empty($oTmpCriteria)) { + if (!empty($tmpCriteria)) { $criteria->add( $criteria->getNewCriterion($listPeer::APP_TITLE, '%' . $search . '%', Criteria::LIKE)->addOr( $criteria->getNewCriterion($listPeer::APP_TAS_TITLE, '%' . $search . '%', Criteria::LIKE)->addOr( $criteria->getNewCriterion($listPeer::APP_PRO_TITLE, '%' . $search . '%', Criteria::LIKE)->addOr( $criteria->getNewCriterion($listPeer::APP_NUMBER, $search, Criteria::EQUAL)->addOr( - $oTmpCriteria + $tmpCriteria )))) ); } else { @@ -3585,6 +3555,58 @@ class Cases } } + /** + * Define the criteria according to the column type + * + * @param string $fieldType + * @param string $column + * @param string $search + * + * @return Criteria + */ + private function defineCriteriaByColumnType($fieldType, $column, $search) + { + $newCriteria = new Criteria("workflow"); + + switch ($fieldType) { + case CreoleTypes::BOOLEAN: + $criteria = $newCriteria->getNewCriterion($column, $search, Criteria::EQUAL); + break; + case CreoleTypes::BIGINT: + case CreoleTypes::INTEGER: + case CreoleTypes::SMALLINT: + case CreoleTypes::TINYINT: + $criteria = $newCriteria->getNewCriterion($column, $search, Criteria::EQUAL); + break; + case CreoleTypes::REAL: + case CreoleTypes::DECIMAL: + case CreoleTypes::DOUBLE: + case CreoleTypes::FLOAT: + $criteria = $newCriteria->getNewCriterion($column, $search, Criteria::LIKE); + break; + case CreoleTypes::CHAR: + case CreoleTypes::LONGVARCHAR: + case CreoleTypes::VARCHAR: + $criteria = $newCriteria->getNewCriterion($column, "%" . $search . "%", Criteria::LIKE); + break; + case CreoleTypes::DATE: + case CreoleTypes::TIME: + case CreoleTypes::TIMESTAMP://DATETIME + //@todo use the same constant in other places + if (preg_match(UtilDateTime::REGEX_IS_DATE, + $search, $arrayMatch)) { + $criteria = $newCriteria->getNewCriterion($column, $search, Criteria::GREATER_EQUAL); + } else { + $criteria = $newCriteria->getNewCriterion($column, $search, Criteria::EQUAL); + } + break; + default: + $criteria = $newCriteria->getNewCriterion($column, $search, Criteria::EQUAL); + } + + return $criteria; + } + /** * This function get the table.column by order by the result * We can include the additional table related to the custom cases list diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/InputDocument.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/InputDocument.php index 1b73cb143..a2f76f27c 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/InputDocument.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/InputDocument.php @@ -937,7 +937,7 @@ class InputDocument */ public function uploadFileCase($files, $caseInstance, $aData, $userUid, $appUid, $delIndex) { - ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) { + ValidationUploadedFiles::getValidationUploadedFiles()->dispatch(function($validator) { G::SendMessageText($validator->getMessage(), "ERROR"); $url = explode("sys" . config("system.workspace"), $_SERVER['HTTP_REFERER']); G::header("location: " . "/sys" . config("system.workspace") . $url[1]); diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/OutputDocument.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/OutputDocument.php index ee9750850..553dd35e5 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/OutputDocument.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/OutputDocument.php @@ -1,6 +1,9 @@ load($outputID); $Fields = $oCase->loadCase($sApplication); - $sFilename = preg_replace('[^A-Za-z0-9_]', '_', \G::replaceDataField($aOD['OUT_DOC_FILENAME'], $Fields['APP_DATA'])); + $outDocFile = replacePrefixes($aOD['OUT_DOC_FILENAME']); + $sFilename = preg_replace('[^A-Za-z0-9_]', '_', \G::replaceDataField($outDocFile, $Fields['APP_DATA'])); require_once(PATH_TRUNK . "workflow" . PATH_SEP . "engine" . PATH_SEP . "classes" . PATH_SEP . "model" . PATH_SEP . "AppFolder.php"); require_once(PATH_TRUNK . "workflow" . PATH_SEP . "engine" . PATH_SEP . "classes" . PATH_SEP . "model" . PATH_SEP . "AppDocument.php"); //Get the Custom Folder ID (create if necessary) @@ -591,21 +595,31 @@ class OutputDocument } } - /* + /** * Generate the output document - * @param string $sUID - * @param array $aFields - * @param string $sPath - * @return variant + * + * @param string $outDocUid + * @param array $caseFields + * @param string $path + * @param string $filename + * @param string $content + * @param bool $landscape + * @param string $typeDocsToGen + * @param array $properties + * @param string $application + * + * @return mixed + * + * @see this->addCasesOutputDocument() */ - public function generate($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape = false, $sTypeDocToGener = 'BOTH', $aProperties = array(), $sApplication) + public function generate($outDocUid, $caseFields, $path, $filename, $content, $landscape = false, $typeDocsToGen = 'BOTH', $properties = [], $application = '') { - if (($sUID != '') && is_array($aFields) && ($sPath != '')) { - $sContent = \G::replaceDataGridField($sContent, $aFields); - \G::verifyPath($sPath, true); + if (($outDocUid != '') && is_array($caseFields) && ($path != '')) { + $content = G::replaceDataGridField($content, $caseFields, true, true); + G::verifyPath($path, true); //Start - Create .doc - $oFile = fopen($sPath . $sFilename . '.doc', 'wb'); - $size = array(); + $fp = fopen($path . $filename . '.doc', 'wb'); + $size = []; $size["Letter"] = "216mm 279mm"; $size["Legal"] = "216mm 357mm"; $size["Executive"] = "184mm 267mm"; @@ -626,6 +640,7 @@ class OutputDocument $size["Screenshot640"] = "640mm 480mm"; $size["Screenshot800"] = "800mm 600mm"; $size["Screenshot1024"] = "1024mm 768mm"; + $sizeLandscape = []; $sizeLandscape["Letter"] = "279mm 216mm"; $sizeLandscape["Legal"] = "357mm 216mm"; $sizeLandscape["Executive"] = "267mm 184mm"; @@ -646,31 +661,31 @@ class OutputDocument $sizeLandscape["Screenshot640"] = "480mm 640mm"; $sizeLandscape["Screenshot800"] = "600mm 800mm"; $sizeLandscape["Screenshot1024"] = "768mm 1024mm"; - if (!isset($aProperties['media'])) { - $aProperties['media'] = 'Letter'; + if (!isset($properties['media'])) { + $properties['media'] = 'Letter'; } - if ($sLandscape) { - $media = $sizeLandscape[$aProperties['media']]; + if ($landscape) { + $media = $sizeLandscape[$properties['media']]; } else { - $media = $size[$aProperties['media']]; + $media = $size[$properties['media']]; } $marginLeft = '15'; - if (isset($aProperties['margins']['left'])) { - $marginLeft = $aProperties['margins']['left']; + if (isset($properties['margins']['left'])) { + $marginLeft = $properties['margins']['left']; } $marginRight = '15'; - if (isset($aProperties['margins']['right'])) { - $marginRight = $aProperties['margins']['right']; + if (isset($properties['margins']['right'])) { + $marginRight = $properties['margins']['right']; } $marginTop = '15'; - if (isset($aProperties['margins']['top'])) { - $marginTop = $aProperties['margins']['top']; + if (isset($properties['margins']['top'])) { + $marginTop = $properties['margins']['top']; } $marginBottom = '15'; - if (isset($aProperties['margins']['bottom'])) { - $marginBottom = $aProperties['margins']['bottom']; + if (isset($properties['margins']['bottom'])) { + $marginBottom = $properties['margins']['bottom']; } - fwrite($oFile, ' @@ -715,40 +730,40 @@ class OutputDocument
'); - fwrite($oFile, $sContent); - fwrite($oFile, "\n
\n\n"); - fclose($oFile); + fwrite($fp, $content); + fwrite($fp, "\n
\n\n"); + fclose($fp); /* End - Create .doc */ - if ($sTypeDocToGener == 'BOTH' || $sTypeDocToGener == 'PDF') { - $oFile = fopen($sPath . $sFilename . '.html', 'wb'); - fwrite($oFile, $sContent); - fclose($oFile); + if ($typeDocsToGen == 'BOTH' || $typeDocsToGen == 'PDF') { + $fp = fopen($path . $filename . '.html', 'wb'); + fwrite($fp, $content); + fclose($fp); /* Start - Create .pdf */ - if (isset($aProperties['report_generator'])) { - switch ($aProperties['report_generator']) { + if (isset($properties['report_generator'])) { + switch ($properties['report_generator']) { case 'TCPDF': - $o = new \OutputDocument(); - if (strlen($sContent) == 0) { + $o = new ClassesOutputDocument(); + if (strlen($content) == 0) { libxml_use_internal_errors(true); - $o->generateTcpdf($sUID, $aFields, $sPath, $sFilename, ' ', $sLandscape, $aProperties); + $o->generateTcpdf($outDocUid, $caseFields, $path, $filename, ' ', $landscape, $properties); libxml_use_internal_errors(false); } else { - $o->generateTcpdf($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape, $aProperties); + $o->generateTcpdf($outDocUid, $caseFields, $path, $filename, $content, $landscape, $properties); } break; case 'HTML2PDF': default: - $this->generateHtml2ps_pdf($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape, $aProperties, $sApplication); + $this->generateHtml2ps_pdf($outDocUid, $caseFields, $path, $filename, $content, $landscape, $properties, $application); break; } } else { - $this->generateHtml2ps_pdf($sUID, $aFields, $sPath, $sFilename, $sContent, $sLandscape, $aProperties); + $this->generateHtml2ps_pdf($outDocUid, $caseFields, $path, $filename, $content, $landscape, $properties); } } - //end if $sTypeDocToGener + //end if $typeDocsToGen /* End - Create .pdf */ } else { - return \PEAR::raiseError( + return PEAR::raiseError( null, G_ERROR_USER_UID, null, diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/DynaForm.php b/workflow/engine/src/ProcessMaker/BusinessModel/DynaForm.php index d2c1bb2a9..2c5f74e19 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/DynaForm.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/DynaForm.php @@ -966,9 +966,10 @@ class DynaForm if ($record['DYN_VERSION'] === 0) { $record['DYN_VERSION'] = 1; } - + //to do, this line should be removed. Related to PMC-196. + $record['DYN_CONTENT'] = G::fixStringCorrupted($record['DYN_CONTENT']); $record['DYN_CONTENT'] = preg_replace_callback("/\\\\u([a-f0-9]{4})/", function ($m) { - return "iconv('UCS-4LE','UTF-8',pack('V', hexdec('U$m[1]')))"; + return iconv('UCS-4LE', 'UTF-8', pack('V', hexdec('U' . $m[1]))); }, $record['DYN_CONTENT']); return array( @@ -977,7 +978,7 @@ class DynaForm $this->getFieldNameByFormatFieldName('DYN_DESCRIPTION') => $record['DYN_DESCRIPTION'] . '', $this->getFieldNameByFormatFieldName('DYN_TYPE') => $record['DYN_TYPE'] . '', $this->getFieldNameByFormatFieldName('DYN_CONTENT') => $record['DYN_CONTENT'] . '', - $this->getFieldNameByFormatFieldName('DYN_VERSION') => (int)$record['DYN_VERSION'], + $this->getFieldNameByFormatFieldName('DYN_VERSION') => (int) $record['DYN_VERSION'], $this->getFieldNameByFormatFieldName('DYN_UPDATE_DATE') => $record['DYN_UPDATE_DATE'] ); } catch (\Exception $e) { diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/EmailEvent.php b/workflow/engine/src/ProcessMaker/BusinessModel/EmailEvent.php index f4a0f2a1b..1ecf359ea 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/EmailEvent.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/EmailEvent.php @@ -14,6 +14,7 @@ use ProcessMaker\Util\Common; use Propel; use ResultSet; use UsersPeer; +use WsBase; class EmailEvent { @@ -455,11 +456,13 @@ class EmailEvent * @param string $prj_uid Unique id of Project * @param string $eventUid Unique id of event * @param array $arrayApplicationData Case data + * @param int $tasId id of task * * @return void * @throws Exception + * @see \Derivation::executeEvent() */ - public function sendEmail($appUID, $prj_uid, $eventUid, $arrayApplicationData) + public function sendEmail($appUID, $prj_uid, $eventUid, $arrayApplicationData, $tasId = 0) { if (!$this->existsEvent($prj_uid, $eventUid)) { throw new Exception(G::LoadTranslation('ID_EMAIL_EVENT_DEFINITION_DOES_NOT_EXIST')); @@ -511,7 +514,9 @@ class EmailEvent } } if (!empty($emailTo)) { - PMFSendMessage( + $ws = new WsBase(); + $ws->setTaskId($tasId); + $ws->sendMessage( $appUID, G::buildFrom($configEmailData), $emailTo, @@ -523,7 +528,9 @@ class EmailEvent [], true, 0, - $configEmailData + $configEmailData, + 0, + WsBase::MESSAGE_TYPE_EMAIL_EVENT ); } else { Bootstrap::registerMonolog( diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/EmailServer.php b/workflow/engine/src/ProcessMaker/BusinessModel/EmailServer.php index 7516bccd2..0f6dfaf45 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/EmailServer.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/EmailServer.php @@ -8,6 +8,7 @@ use G; use ProcessMaker\Core\System; use SpoolRun; use TemplatePower; +use WsBase; class EmailServer { @@ -156,6 +157,7 @@ class EmailServer * * @return array, return array with result of send test mail * @throws Exception + * @see EmailServer->testConnectionByStep() */ public function sendTestMail(array $arrayData) { @@ -203,7 +205,7 @@ class EmailServer '', '', 0, - 'TEST', + WsBase::MESSAGE_TYPE_TEST_EMAIL, G::LoadTranslation("ID_MESS_TEST_SUBJECT"), G::buildFrom($configuration), $arrayData["TO"], diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/InputDocument.php b/workflow/engine/src/ProcessMaker/BusinessModel/InputDocument.php index 62122e104..3fc84d723 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/InputDocument.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/InputDocument.php @@ -1,7 +1,10 @@ doPostInputDocument() + * @link https://wiki.processmaker.com/3.0/Input_Documents#Creating_Input_Documents */ public function create($processUid, $arrayData) { @@ -310,6 +316,8 @@ class InputDocument $flagDataDestinationPath = (isset($arrayData["INP_DOC_DESTINATION_PATH"]))? 1 : 0; $flagDataTags = (isset($arrayData["INP_DOC_TAGS"]))? 1 : 0; + $this->throwExceptionIfMaximumFileSizeExceed(intval($arrayData["INP_DOC_MAX_FILESIZE"]), $arrayData["INP_DOC_MAX_FILESIZE_UNIT"]); + //Create $inputDocument = new \InputDocument(); @@ -348,8 +356,11 @@ class InputDocument * * @param string $inputDocumentUid Unique id of InputDocument * @param array $arrayData Data - * - * return array Return data of the InputDocument updated + * + * @return array Return data of the InputDocument updated + * + * @see \ProcessMaker\Services\Api\Project\InputDocument->doPutInputDocument() + * @link https://wiki.processmaker.com/3.0/Input_Documents#Creating_Input_Documents */ public function update($inputDocumentUid, $arrayData) { @@ -374,6 +385,8 @@ class InputDocument if (isset($arrayData["INP_DOC_TITLE"])) { $this->throwExceptionIfExistsTitle($processUid, $arrayData["INP_DOC_TITLE"], $this->arrayFieldNameForException["inputDocumentTitle"], $inputDocumentUid); } + + $this->throwExceptionIfMaximumFileSizeExceed(intval($arrayData["INP_DOC_MAX_FILESIZE"]), $arrayData["INP_DOC_MAX_FILESIZE_UNIT"]); //Update $arrayData["INP_DOC_UID"] = $inputDocumentUid; @@ -519,7 +532,7 @@ class InputDocument * * @param string $inputDocumentUid Unique id of InputDocument * - * return array Return an array with data of an InputDocument + * @return array Return an array with data of an InputDocument */ public function getInputDocument($inputDocumentUid) { @@ -544,5 +557,71 @@ class InputDocument throw $e; } } + + /** + * Throw exception if maximum file size exceed to php directives. + * + * @param int $value + * @param string $unit + * @throws Exception + * + * @see ProcessMaker\BusinessModel\InputDocument->create() + * @see ProcessMaker\BusinessModel\InputDocument->update() + * @link https://wiki.processmaker.com/3.2/Input_Documents + */ + public function throwExceptionIfMaximumFileSizeExceed($value, $unit) + { + //The value of 'INP_DOC_MAX_FILESIZE_UNIT' can only take two values: 'KB'and 'MB'. + if ($unit === "MB") { + $value = $value * (1024 ** 2); + } + if ($unit === "KB") { + $value = $value * (1024 ** 1); + } + $object = $this->getMaxFileSize(); + if ($object->uploadMaxFileSizeBytes < $value) { + throw new Exception(G::LoadTranslation("ID_THE_MAXIMUM_VALUE_OF_THIS_FIELD_IS", [$object->uploadMaxFileSize])); + } + } + + /** + * To upload large files, post_max_size value must be larger than upload_max_filesize. + * Generally speaking, memory_limit should be larger than post_max_size. When an integer + * is used, the value is measured in bytes. The shorthand notation may also be used. + * If the size of post data is greater than post_max_size, the $_POST and $_FILES + * superglobals are empty. + * + * @return object + * + * @see ProcessMaker\BusinessModel\InputDocument->throwExceptionIfMaximumFileSizeExceed() + * @link https://wiki.processmaker.com/3.2/Input_Documents + * @link http://php.net/manual/en/faq.using.php#faq.using.shorthandbytes + */ + public function getMaxFileSize() + { + $phpShorthandByte = new PhpShorthandByte(); + $postMaxSize = ini_get("post_max_size"); + $postMaxSizeBytes = $phpShorthandByte->valueToBytes($postMaxSize); + $uploadMaxFileSize = ini_get("upload_max_filesize"); + $uploadMaxFileSizeBytes = $phpShorthandByte->valueToBytes($uploadMaxFileSize); + + if ($postMaxSizeBytes < $uploadMaxFileSizeBytes) { + $uploadMaxFileSize = $postMaxSize; + $uploadMaxFileSizeBytes = $postMaxSizeBytes; + } + + //according to the acceptance criteria the information is always shown in MBytes + $uploadMaxFileSizeMBytes = $uploadMaxFileSizeBytes / (1024 ** 2); //conversion constant + $uploadMaxFileSizeUnit = "MB"; //short processmaker notation, https://wiki.processmaker.com/3.0/File_control#Size_Unity + $uploadMaxFileSizePhpUnit = "M"; //short php notation, http://php.net/manual/en/faq.using.php#faq.using.shorthandbytes + + $result = [ + "uploadMaxFileSize" => $phpShorthandByte->getFormatBytes($uploadMaxFileSizeMBytes . $uploadMaxFileSizePhpUnit), + "uploadMaxFileSizeBytes" => $uploadMaxFileSizeBytes, + "uploadMaxFileSizeMBytes" => $uploadMaxFileSizeMBytes, + "uploadMaxFileSizeUnit" => $uploadMaxFileSizeUnit + ]; + return (object) $result; + } } diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Light.php b/workflow/engine/src/ProcessMaker/BusinessModel/Light.php index 8ee6a3b2d..4cbdb2c48 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Light.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Light.php @@ -415,6 +415,7 @@ class Light $oCase = new Cases(); $Fields = $oCase->loadCase($cas_uid); + //@todo Find a better way to define session variables $_SESSION["APPLICATION"] = $cas_uid; $_SESSION["PROCESS"] = $prj_uid; $_SESSION["TASK"] = $act_uid; @@ -453,6 +454,7 @@ class Light try { $oCase = new Cases(); $Fields = $oCase->loadCase($app_uid); + //@todo Find a better way to define session variables $_SESSION["APPLICATION"] = $app_uid; $_SESSION["PROCESS"] = $Fields['PRO_UID']; $_SESSION["TASK"] = $tas_uid; @@ -1488,6 +1490,7 @@ class Light } $response['listLanguage'] = $languagesList; if (isset($params['fileLimit']) && $params['fileLimit']) { + //to do: ProcessMaker\BusinessModel\InputDocument->getMaxFileSize() $postMaxSize = $this->return_bytes(ini_get('post_max_size')); $uploadMaxFileSize = $this->return_bytes(ini_get('upload_max_filesize')); if ($postMaxSize < $uploadMaxFileSize) { diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Light/PushMessageAndroid.php b/workflow/engine/src/ProcessMaker/BusinessModel/Light/PushMessageAndroid.php index 98c02649d..456904e90 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Light/PushMessageAndroid.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Light/PushMessageAndroid.php @@ -17,9 +17,9 @@ use ProcessMaker\Core\System; class PushMessageAndroid { - private $url = 'https://android.googleapis.com/gcm/send'; - private $serverApiKey = "AIzaSyBO-VLXGhjf0PPlwmPFTPQEKIBfVDydLAk"; - private $devices = array(); + private $url = 'https://fcm.googleapis.com/fcm/send'; + private $serverApiKey = "AAAAMvip2iU:APA91bHFAvHmCsSh0zbRaC9Xo2EPIbbRYzehkFAKUdXmj_ZVBOOO52npae183LYUONHjNPHaKo1MqT4BWiEuTF7HVEMfwn05XOA-h1LQ_bJ0ezAA35l-wADPq5VtKDiHT1VFGW1oeU7L"; + private $devices = []; private $numberDevices = 0; /** @@ -78,24 +78,24 @@ class PushMessageAndroid } if (!is_null($data)) { - $fields = array( + $fields = [ 'registration_ids' => $this->devices, - 'data' => array( - "message" => $message, - "data" => $data - ), - ); + 'notification' => [ + "body" => $message, + "data" => $data, + ], + ]; } else { - $fields = array( + $fields = [ 'registration_ids' => $this->devices, - 'data' => array("message" => $message), - ); + 'data' => ["message" => $message], + ]; } - $headers = array( + $headers = [ 'Authorization: key=' . $this->serverApiKey, 'Content-Type: application/json' - ); + ]; // Open connection $ch = curl_init(); diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/ProcessMap.php b/workflow/engine/src/ProcessMaker/BusinessModel/ProcessMap.php index 068e795ef..ae0f84d5d 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/ProcessMap.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/ProcessMap.php @@ -117,7 +117,7 @@ class ProcessMap $tmpData[5] = ""; $tmpData[6] = $lanes['lan_name']; $tmpData[7] = ""; - $tmpData[8] = $lanes['lan_uid']; + $tmpData[8] = array_key_exists('lan_uid', $lanes) ? $lanes['lan_uid']: ""; $tmpData[9] = ""; $tmpData[10] = $lanes['bou_container']; @@ -719,7 +719,7 @@ class ProcessMap if($element['bou_container'] != "bpmnDiagram"){ $resRec = $this->getNewPoints($element['bou_element'],$element['bou_container']); } - if($element['lns_uid'] == $idElement || $element['lan_uid'] == $idElement){ + if ($element['lns_uid'] == $idElement || (array_key_exists('lan_uid', $element) ? $element['lan_uid'] == $idElement : false)) { $result = array($element['bou_x'] + $resRec[0],$element['bou_y'] + $resRec[1]); } } diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/ReportTable.php b/workflow/engine/src/ProcessMaker/BusinessModel/ReportTable.php index 387257903..e50f4a47e 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/ReportTable.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/ReportTable.php @@ -4,6 +4,7 @@ namespace ProcessMaker\BusinessModel; use AdditionalTables; use AdditionalTablesPeer; +use Configurations; use G; use Exception; @@ -328,6 +329,11 @@ class ReportTable * * @param array $arrayData * @param bool $flagAlterTable + * + * @see pmTablesProxy->save() + * @see ProcessMaker\BusinessModel\ReportTable->createStructureOfTables() + * @see Table->validateTableBeforeUpdate() + * @link https://wiki.processmaker.com/3.1/Report_Tables * * @return object */ @@ -560,6 +566,7 @@ class ReportTable //Delete Report Table $resultDeleteReportTable = $pmTablesProxy->delete($obj); } + $this->updateConfigurationCaseList($additionalTableUid, $columns); } catch (Exception $e) { $buildResult = ob_get_contents(); @@ -578,11 +585,126 @@ class ReportTable $result->trace = $e->getTraceAsString(); } - //Return return $result; } + /** + * Update the Custom Case List fields configuration. + * + * @param array $columns + * + * @see ProcessMaker\BusinessModel\ReportTable->saveStructureOfTable() + * @link https://wiki.processmaker.com/3.1/Report_Tables + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ + public function updateConfigurationCaseList($addTabUid, $columns) + { + $actions = [ + "todo", "draft", "sent", "unassigned", "paused", "completed", "cancelled" + ]; + $conf = new Configurations(); + foreach ($actions as $action) { + $confCasesList = $conf->loadObject("casesList", $action, "", "", ""); + $sw = is_array($confCasesList) && !empty($confCasesList) && !empty($confCasesList['PMTable']) && $confCasesList['PMTable'] === $addTabUid; + if ($sw) { + $this->addFieldsToCustomCaseList($confCasesList['first']['data'], $confCasesList['second']['data'], $columns); + $this->removeFieldsFromCustomCaseList($confCasesList['first']['data'], $columns); + $this->removeFieldsFromCustomCaseList($confCasesList['second']['data'], $columns); + $conf->saveObject($confCasesList, "casesList", $action); + } + } + } + + /** + * Add fields to Custom Case List. + * @param array $data1 + * @param array $data2 + * @param array $columns + * + * @see ProcessMaker\BusinessModel\ReportTable->saveStructureOfTable() + * @link https://wiki.processmaker.com/3.1/Report_Tables + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ + public function addFieldsToCustomCaseList(&$data1, $data2, $columns) + { + $all = []; + $type = 'PM Table'; + $this->loadFieldTypeValues($data1, $all, $type); + $this->loadFieldTypeValues($data2, $all, $type); + foreach ($all as $value) { + foreach ($columns as $index => $column) { + if ($value['name'] === $column->field_name) { + unset($columns[$index]); + break; + } + } + } + $defaults = ["APP_UID", "APP_NUMBER", "APP_STATUS"]; + foreach ($defaults as $value) { + foreach ($columns as $index => $column) { + if ($value === $column->field_name) { + unset($columns[$index]); + break; + } + } + } + foreach ($columns as $value) { + $data1[] = [ + "name" => $column->field_name, + "fieldType" => $type + ]; + } + } + + /** + * Load field type values. + * + * @param array $fields + * @param array $all + * @param string $type + */ + private function loadFieldTypeValues($fields, array &$all, $type) + { + foreach ($fields as $value) { + if ($value['fieldType'] === $type) { + $all[] = $value; + } + } + } + + /** + * Remove fields from Custom Cases List. + * + * @param array $data + * @param array $columns + * + * @see ProcessMaker\BusinessModel\ReportTable->saveStructureOfTable() + * @link https://wiki.processmaker.com/3.1/Report_Tables + * @link https://wiki.processmaker.com/3.2/Cases_List_Builder#Installation_and_Configuration + */ + public function removeFieldsFromCustomCaseList(&$data, $columns) + { + $n = count($data); + for ($key = 0; $key < $n; $key++) { + if ($data[$key]['fieldType'] === 'PM Table') { + $remove = true; + foreach ($columns as $column) { + if ($data[$key]['name'] === $column->field_name) { + $remove = false; + break; + } + } + if ($remove === true) { + unset($data[$key]); + $data = array_values($data); + $key = 0; + $n = count($data); + } + } + } + } + /** * Create the structure of tables * diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/ScriptTask.php b/workflow/engine/src/ProcessMaker/BusinessModel/ScriptTask.php index 371eb0bae..509b46b93 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/ScriptTask.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/ScriptTask.php @@ -10,6 +10,7 @@ use PMScript; use ResultSet; use ScriptTaskPeer; use TaskPeer; +use Triggers as ModelTriggers; use TriggersPeer; class ScriptTask @@ -602,13 +603,16 @@ class ScriptTask } /** - * Execute Script + * Execute the trigger related to the script task * * @param string $activityUid Unique id of task * @param array $arrayApplicationData Case data * * @return array * @throws Exception + * + * @see Derivation::derivate() + * @link https://wiki.processmaker.com/3.1/Tasks#ScriptTask */ public function execScriptByActivityUid($activityUid, array $arrayApplicationData) { @@ -625,34 +629,35 @@ class ScriptTask if ($rsCriteria->next()) { $row = $rsCriteria->getRow(); $scriptTasObjUid = $row["SCRTAS_OBJ_UID"]; - $trigger = TriggersPeer::retrieveByPK($scriptTasObjUid); + $trigger = new ModelTriggers(); + $triggersList[] = $trigger->load($scriptTasObjUid); - if (!is_null($trigger)) { - //We will be update the status before execute the trigger related to the script task + if (!empty($triggersList)){ $case = new ClassesCases(); - $result = $case->updateCase($arrayApplicationData["APP_UID"], $arrayApplicationData); + //We will be update the status before execute the trigger related to the script task + $case->updateCase($arrayApplicationData["APP_UID"], $arrayApplicationData); - //Some Pmf functions uses this global variable $oPMScript for review the aFields defined - global $oPMScript; - $oPMScript = new PMScript(); - $oPMScript->setDataTrigger($trigger->toArray(BasePeer::TYPE_FIELDNAME)); - $oPMScript->setFields($arrayApplicationData["APP_DATA"]); - $oPMScript->setScript($trigger->getTriWebbot()); - $oPMScript->setExecutedOn(PMScript::SCRIPT_TASK); - $oPMScript->execute(); + //Execute the trigger defined in the script task + $arrayApplicationData['APP_DATA'] = $case->executeTriggerFromList( + $triggersList, + $arrayApplicationData['APP_DATA'], + 'SCRIPT_TASK', + '', + '' + ); - if (isset($oPMScript->aFields["__ERROR__"])) { - G::log("Case Uid: " . $arrayApplicationData["APP_UID"] . ", Error: " . $oPMScript->aFields["__ERROR__"], + $case->updateCase($arrayApplicationData['APP_UID'], $arrayApplicationData); + + if (isset($arrayApplicationData['APP_DATA']['__ERROR__'])) { + G::log("Case Uid: " . $arrayApplicationData["APP_UID"] . ", Error: " . $arrayApplicationData['APP_DATA']['__ERROR__'], PATH_DATA, "ScriptTask.log"); } - $arrayApplicationData["APP_DATA"] = $oPMScript->aFields; - $result = $case->updateCase($arrayApplicationData["APP_UID"], $arrayApplicationData); } } } //Return - return $arrayApplicationData["APP_DATA"]; + return $arrayApplicationData['APP_DATA']; } catch (Exception $e) { throw $e; } diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/TimerEvent.php b/workflow/engine/src/ProcessMaker/BusinessModel/TimerEvent.php index 3496b1268..c997f2508 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/TimerEvent.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/TimerEvent.php @@ -1200,11 +1200,14 @@ class TimerEvent /** * Start/Continue case by Timer-Event - * + * * @param string $datetime Datetime (yyyy-mm-dd hh:ii:ss) - * @param bool $frontEnd Flag to represent the terminal front-end - * - * return void + * @param bool $frontEnd Flag to represent the terminal front-end + * @throws \Exception + * + * @see workflow/engine/bin/cron_single.php + * @link https://wiki.processmaker.com/3.3/Actions_by_Email + * @link https://wiki.processmaker.com/3.2/Executing_cron.php */ public function startContinueCaseByTimerEvent($datetime, $frontEnd = false) { @@ -1622,6 +1625,8 @@ class TimerEvent $delIndex = $row["DEL_INDEX"]; $delDelegateDate = $row["DEL_DELEGATE_DATE"]; $bpmnEventName = $row["EVN_NAME"]; + $taskUid = !empty($arrayApplicationData['APP_DATA']) && !empty($arrayApplicationData['APP_DATA']['TASK']) ? + $arrayApplicationData['APP_DATA']['TASK'] : ''; //Continue the case $continueCaseDate = $delDelegateDate; diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/User.php b/workflow/engine/src/ProcessMaker/BusinessModel/User.php index 6bf7818dd..e5d18ee37 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/User.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/User.php @@ -21,6 +21,7 @@ use IsoCountryPeer; use IsoLocationPeer; use IsoSubdivisionPeer; use ListParticipatedLast; +use OauthClients; use PMmemcached; use ProcessMaker\BusinessModel\ProcessSupervisor as BmProcessSupervisor; use ProcessMaker\Plugins\PluginRegistry; @@ -1023,6 +1024,9 @@ class User //Update in workflow $result = $user->update($arrayData); + if (isset($arrayData['USR_STATUS'])) { + $arrayData['USR_STATUS'] == 'INACTIVE' ? RBAC::destroySessionUser($userUid) : null; + } //Save Calendar assigment if (isset($arrayData["USR_CALENDAR"])) { @@ -1330,6 +1334,9 @@ class User $criteria->add(DashletInstancePeer::DAS_INS_OWNER_UID, $UID); $criteria->add(DashletInstancePeer::DAS_INS_OWNER_TYPE, 'USER'); DashletInstancePeer::doDelete($criteria); + //Destroy session after delete user + RBAC::destroySessionUser($usrUid); + (new OauthClients())->removeByUser($usrUid); } } catch (Exception $e) { throw $e; @@ -1998,4 +2005,111 @@ class User return $isSupervisor; } } + + /** + * It changes the password of the user specified by its identifier, optionally + * the value of $userLang can be sent, otherwise the system value is taken. + * In case of success, the updated user returns. + * + * @global object $RBAC + * @param string $usrUid + * @param string $usrPassword + * @param string $userLang + * + * @return string + * + * @see workflow/engine/methods/login/authentication.php + * @see workflow/engine/methods/login/changePassword.php + * @link https://wiki.processmaker.com/3.0/Managing_Users#Creating_New_Users + */ + public function changePassword($usrUid, $usrPassword, $userLang = "") + { + global $RBAC; + + $users = new Users(); + $user = $users->load($usrUid); + + $data = []; + $data['USR_UID'] = $user['USR_UID']; + $data['USR_USERNAME'] = $user['USR_USERNAME']; + $data['USR_PASSWORD'] = Bootstrap::hashPassword($usrPassword); + $data['USR_FIRSTNAME'] = $user['USR_FIRSTNAME']; + $data['USR_LASTNAME'] = $user['USR_LASTNAME']; + $data['USR_EMAIL'] = $user['USR_EMAIL']; + $data['USR_DUE_DATE'] = $user['USR_DUE_DATE']; + $data['USR_UPDATE_DATE'] = date('Y-m-d H:i:s'); + + $RBAC->updateUser($data, $user['USR_ROLE']); + + $data['USR_COUNTRY'] = $user['USR_COUNTRY']; + $data['USR_CITY'] = $user['USR_CITY']; + $data['USR_LOCATION'] = $user['USR_LOCATION']; + $data['USR_ADDRESS'] = $user['USR_ADDRESS']; + $data['USR_PHONE'] = $user['USR_PHONE']; + $data['USR_ZIP_CODE'] = $user['USR_ZIP_CODE']; + $data['USR_POSITION'] = $user['USR_POSITION']; + + $users->update($data); + + $usersProperties = new UsersProperties(); + $userProperty = $usersProperties->load($usrUid); + $history = unserialize($userProperty['USR_PASSWORD_HISTORY']); + + if (!is_array($history)) { + $history = []; + } + + if (!defined('PPP_PASSWORD_HISTORY')) { + define('PPP_PASSWORD_HISTORY', 0); + } + + if (PPP_PASSWORD_HISTORY > 0) { + if (count($history) >= PPP_PASSWORD_HISTORY) { + array_shift($history); + } + $history[] = $usrPassword; + } + + $userProperty['USR_LAST_UPDATE_DATE'] = date('Y-m-d H:i:s'); + $userProperty['USR_LOGGED_NEXT_TIME'] = 0; + $userProperty['USR_PASSWORD_HISTORY'] = serialize($history); + + $usersProperties->update($userProperty); + + if (class_exists('redirectDetail')) { + + if (isset($RBAC->aUserInfo['PROCESSMAKER']['ROLE']['ROL_CODE'])) { + $userRole = $RBAC->aUserInfo['PROCESSMAKER']['ROLE']['ROL_CODE']; + } + $pluginRegistry = PluginRegistry::loadSingleton(); + + $redirectLogin = $pluginRegistry->getRedirectLogins(); + if (isset($redirectLogin)) { + if (is_array($redirectLogin)) { + foreach ($redirectLogin as $detail) { + if (isset($detail->sPathMethod)) { + if ($detail->equalRoleCodeTo($userRole)) { + $user['__REDIRECT_PATH__'] = '/sys' . config('system.workspace') . '/' . SYS_LANG . '/' . SYS_SKIN . '/' . $detail->getPathMethod(); + return $user; + } + } + } + } + } + } + + $lang = ""; + if ($userLang !== "") { + $lang = $userLang; + } else { + if (defined('SYS_LANG')) { + $lang = SYS_LANG; + } else { + $lang = 'en'; + } + } + $location = $usersProperties->redirectTo($usrUid, $lang); + $user['__REDIRECT_PATH__'] = $location; + return $user; + } } diff --git a/workflow/engine/src/ProcessMaker/Core/System.php b/workflow/engine/src/ProcessMaker/Core/System.php index 85e449cb4..ae37dea92 100644 --- a/workflow/engine/src/ProcessMaker/Core/System.php +++ b/workflow/engine/src/ProcessMaker/Core/System.php @@ -1534,7 +1534,8 @@ class System */ public static function getServerProtocol() { - return G::is_https() ? "https://" : "http://"; + $envProtocol = defined("REQUEST_SCHEME") && REQUEST_SCHEME === "https"; + return G::is_https() || $envProtocol ? "https://" : "http://"; } /** @@ -1577,7 +1578,7 @@ class System public static function getServerHost() { $port = self::getServerPort(); - if (!empty($port) && $port != '80') { + if (!empty($port) && $port != '80' && $port != '443') { return self::getServerHostname() . ':' . $port; } return self::getServerHostname(); @@ -1597,11 +1598,25 @@ class System * Get server main path (protocol + host + port + workspace + lang + skin). * * @return string + * @see ProcessMaker\BusinessModel\ProjectUser->projectWsUserCanStartTask() + * @see ProcessMaker\BusinessModel\ProjectUser->userLogin() + * @see ProcessMaker\BusinessModel\WebEntry->getWebEntryDataFromRecord() + * @see ProcessMaker\BusinessModel\WebEntryEvent->getGeneratedLink() + * @see ProcessMaker\Core\System\ActionsByEmailCoreClass->sendActionsByEmail() + * @see ProcessMaker\Core\System\webEntryProxy->checkCredentials() + * @see ProcessMaker\Core\System\webEntryProxy->save() + * @see workflow/engine/classes/ProcessMap.php ProcessMap->listNewWebEntry() + * @see workflow/engine/classes/ProcessMap.php ProcessMap->webEntry() + * @see workflow/engine/controllers/caseSchedulerProxy.php caseSchedulerProxy->checkCredentials() + * @see workflow/engine/methods/cases/cases_SchedulerValidateUser.php + * @see workflow/engine/methods/processes/processes_webEntryGenerate.php + * @see workflow/engine/methods/processes/processes_webEntryValidate.php + * @see workflow/engine/methods/processes/webEntry_Val_Assig.php */ public static function getServerMainPath() { - $conf = new Configurations(); - $skin = defined("SYS_SKIN") ? SYS_SKIN : $conf->getConfiguration('SKIN_CRON', ''); + $config = self::getSystemConfiguration(); + $skin = defined("SYS_SKIN") ? SYS_SKIN : $config['default_skin']; return self::getServerProtocolHost() . '/sys' . config("system.workspace") . '/' . SYS_LANG . '/' . $skin; } diff --git a/workflow/engine/src/ProcessMaker/Model/AppAssignSelfServiceValue.php b/workflow/engine/src/ProcessMaker/Model/AppAssignSelfServiceValue.php new file mode 100644 index 000000000..f2cf56c94 --- /dev/null +++ b/workflow/engine/src/ProcessMaker/Model/AppAssignSelfServiceValue.php @@ -0,0 +1,14 @@ +hasMany(Delegation::class, 'APP_UID', 'APP_UID'); + } + + public function parent() + { + return $this->hasOne(Application::class, 'APP_PARENT', 'APP_UID'); + } + + public function currentUser() + { + return $this->hasOne(User::class, 'APP_CUR_USER', 'USR_UID'); + } +} diff --git a/workflow/engine/src/ProcessMaker/Model/Delegation.php b/workflow/engine/src/ProcessMaker/Model/Delegation.php new file mode 100644 index 000000000..46ee58f7b --- /dev/null +++ b/workflow/engine/src/ProcessMaker/Model/Delegation.php @@ -0,0 +1,333 @@ +belongsTo(Application::class, 'APP_UID', 'APP_UID'); + } + + /** + * Returns the user this delegation belongs to + */ + public function user() + { + return $this->belongsTo(User::class, 'USR_ID', 'USR_ID'); + } + + /** + * Return the process task this belongs to + */ + public function task() + { + return $this->belongsTo(Task::class, 'TAS_ID', 'TAS_ID'); + } + + /** + * Return the process this delegation belongs to + */ + public function process() + { + return $this->belongsTo(Process::class, 'PRO_ID', 'PRO_ID'); + } + + /** + * Searches for delegations which match certain criteria + * + * The query is related to advanced search with different filters + * We can search by process, status of case, category of process, users, delegate date from and to + * + * @param integer $userId The USR_ID to search for (Note, this is no longer the USR_UID) + * @param integer $start for the pagination + * @param integer $limit for the pagination + * @param string $search + * @param integer $process the pro_id + * @param integer $status of the case + * @param string $dir if the order is DESC or ASC + * @param string $sort name of column by sort, can be: + * [APP_NUMBER, APP_TITLE, APP_PRO_TITLE, APP_TAS_TITLE, APP_CURRENT_USER, APP_UPDATE_DATE, DEL_DELEGATE_DATE, DEL_TASK_DUE_DATE, APP_STATUS_LABEL] + * @param string $category uid for the process + * @param date $dateFrom + * @param date $dateTo + * @param string $filterBy name of column for a specific search, can be: [APP_NUMBER, APP_TITLE, TAS_TITLE] + * @return array $result result of the query + */ + + public static function search( + $userId = null, + // Default pagination values + $start = 0, + $limit = 25, + $search = null, + $process = null, + $status = null, + $dir = null, + $sort = null, + $category = null, + $dateFrom = null, + $dateTo = null, + $filterBy = 'APP_TITLE' + ) { + $search = trim($search); + + // Start the query builder, selecting our base attributes + $selectColumns = [ + 'APPLICATION.APP_NUMBER', + 'APPLICATION.APP_UID', + 'APPLICATION.APP_STATUS', + 'APPLICATION.APP_STATUS AS APP_STATUS_LABEL', + 'APPLICATION.PRO_UID', + 'APPLICATION.APP_CREATE_DATE', + 'APPLICATION.APP_FINISH_DATE', + 'APPLICATION.APP_UPDATE_DATE', + 'APPLICATION.APP_TITLE', + 'APP_DELEGATION.USR_UID', + 'APP_DELEGATION.TAS_UID', + 'APP_DELEGATION.USR_ID', + 'APP_DELEGATION.PRO_ID', + 'APP_DELEGATION.DEL_INDEX', + 'APP_DELEGATION.DEL_LAST_INDEX', + 'APP_DELEGATION.DEL_DELEGATE_DATE', + 'APP_DELEGATION.DEL_INIT_DATE', + 'APP_DELEGATION.DEL_FINISH_DATE', + 'APP_DELEGATION.DEL_TASK_DUE_DATE', + 'APP_DELEGATION.DEL_RISK_DATE', + 'APP_DELEGATION.DEL_THREAD_STATUS', + 'APP_DELEGATION.DEL_PRIORITY', + 'APP_DELEGATION.DEL_DURATION', + 'APP_DELEGATION.DEL_QUEUE_DURATION', + 'APP_DELEGATION.DEL_STARTED', + 'APP_DELEGATION.DEL_DELAY_DURATION', + 'APP_DELEGATION.DEL_FINISHED', + 'APP_DELEGATION.DEL_DELAYED', + 'APP_DELEGATION.DEL_DELAY_DURATION', + 'TASK.TAS_TITLE AS APP_TAS_TITLE', + 'TASK.TAS_TYPE AS APP_TAS_TYPE', + ]; + $query = DB::table('APP_DELEGATION')->select(DB::raw(implode(',', $selectColumns))); + + // Add join for task, filtering for task title if needed + // It doesn't make sense for us to search for any delegations that match tasks that are events or web entry + $query->join('TASK', function ($join) use ($filterBy, $search) { + $join->on('APP_DELEGATION.TAS_ID', '=', 'TASK.TAS_ID') + ->whereNotIn('TASK.TAS_TYPE', [ + 'WEBENTRYEVENT', + 'END-MESSAGE-EVENT', + 'START-MESSAGE-EVENT', + 'INTERMEDIATE-THROW', + ]); + if ($filterBy == 'TAS_TITLE' && $search) { + $join->where('TASK.TAS_TITLE', 'LIKE', "%${search}%"); + } + }); + + // Add join for application, taking care of status and filtering if necessary + $query->join('APPLICATION', function ($join) use ($filterBy, $search, $status, $query) { + $join->on('APP_DELEGATION.APP_NUMBER', '=', 'APPLICATION.APP_NUMBER'); + if ($filterBy == 'APP_TITLE' && $search) { + $join->where('APPLICATION.APP_TITLE', 'LIKE', "%${search}%"); + } + // Based on the below, we can further limit the join so that we have a smaller data set based on join criteria + switch ($status) { + case 1: //DRAFT + $join->where('APPLICATION.APP_STATUS_ID', 1); + break; + case 2: //TO_DO + $join->where('APPLICATION.APP_STATUS_ID', 2); + break; + case 3: //COMPLETED + $join->where('APPLICATION.APP_STATUS_ID', 3); + break; + case 4: //CANCELLED + $join->where('APPLICATION.APP_STATUS_ID', 4); + break; + case "PAUSED": + $join->where('APPLICATION.APP_STATUS', 'TO_DO'); + break; + default: //All status + // Don't do anything here, we'll need to do the more advanced where below + } + }); + + // Add join for process, but only for certain scenarios such as category or process + if (($category && !$process) || $sort == 'APP_PRO_TITLE') { + $query->join('PROCESS', function ($join) use ($category) { + $join->on('APP_DELEGATION.PRO_ID', '=', 'PROCESS.PRO_ID'); + if ($category) { + $join->where('PROCESS.PRO_CATEGORY', $category); + } + }); + } + + // Add join for user, but only for certain scenarios as sorting + if ($sort == 'APP_CURRENT_USER') { + $query->join('USERS', function ($join) use ($userId) { + $join->on('APP_DELEGATION.USR_ID', '=', 'USERS.USR_ID'); + }); + } + + // Search for specified user + if ($userId) { + $query->where('APP_DELEGATION.USR_ID', $userId); + } + + // Search for specified process + if ($process) { + $query->where('APP_DELEGATION.PRO_ID', $process); + } + + // Search for an app/case number + if ($filterBy == 'APP_NUMBER' && $search) { + $query->where('APP_DELEGATION.APP_NUMBER', 'LIKE', "%${search}%"); + } + + // Date range filter + if (!empty($dateFrom)) { + $query->where('APP_DELEGATION.DEL_DELEGATE_DATE', '>=', $dateFrom); + } + if (!empty($dateTo)) { + $dateTo = $dateTo . " 23:59:59"; + // This is inclusive + $query->where('APP_DELEGATION.DEL_DELEGATE_DATE', '<=', $dateTo); + } + + // Status Filter + // This is tricky, the below behavior is combined with the application join behavior above + switch ($status) { + case 1: //DRAFT + $query->where('APP_DELEGATION.DEL_THREAD_STATUS', 'OPEN'); + break; + case 2: //TO_DO + $query->where('APP_DELEGATION.DEL_THREAD_STATUS', 'OPEN'); + break; + case 3: //COMPLETED + $query->where('APP_DELEGATION.DEL_LAST_INDEX', 1); + break; + case 4: //CANCELLED + $query->where('APP_DELEGATION.DEL_LAST_INDEX', 1); + break; + case "PAUSED": + // Do nothing, as the app status check for TO_DO is performed in the join above + break; + default: //All statuses. + $query->where(function ($query) { + // Check to see if thread status is open + $query->where('APP_DELEGATION.DEL_THREAD_STATUS', 'OPEN') + ->orWhere(function ($query) { + // Or, we make sure if the thread is closed, and it's the last delegation, and if the app is completed or cancelled + $query->where('APP_DELEGATION.DEL_THREAD_STATUS', 'CLOSED') + ->where('APP_DELEGATION.DEL_LAST_INDEX', 1) + ->whereIn('APPLICATION.APP_STATUS_ID', [3, 4]); + }); + }); + break; + } + + // Add any sort if needed + if($sort) { + switch ($sort) { + case 'APP_NUMBER': + $query->orderBy('APP_DELEGATION.APP_NUMBER', $dir); + break; + case 'APP_PRO_TITLE': + // We can do this because we joined the process table if sorting by it + $query->orderBy('PROCESS.PRO_TITLE', $dir); + break; + case 'APP_TAS_TITLE': + $query->orderBy('TASK.TAS_TITLE', $dir); + break; + case 'APP_CURRENT_USER': + // We can do this because we joined the user table if sorting by it + $query->orderBy('USERS.USR_LASTNAME', $dir); + $query->orderBy('USERS.USR_FIRSTNAME', $dir); + break; + default: + $query->orderBy($sort, $dir); + } + } + + // Add pagination to the query + $query = $query->offset($start) + ->limit($limit); + + // Fetch results and transform to a laravel collection + $results = $query->get(); + + // Transform with additional data + $priorities = ['1' => 'VL', '2' => 'L', '3' => 'N', '4' => 'H', '5' => 'VH']; + $results->transform(function ($item, $key) use ($priorities) { + // Convert to an array as our results must be an array + $item = json_decode(json_encode($item), true); + // If it's assigned, fetch the user + if($item['USR_ID']) { + $user = User::where('USR_ID', $item['USR_ID'])->first(); + } else { + $user = null; + } + $process = Process::where('PRO_ID', $item['PRO_ID'])->first(); + + // Rewrite priority string + if ($item['DEL_PRIORITY']) { + $item['DEL_PRIORITY'] = G::LoadTranslation("ID_PRIORITY_{$priorities[$item['DEL_PRIORITY']]}"); + } + + // Merge in desired application data + if ($item['APP_STATUS']) { + $item['APP_STATUS_LABEL'] = G::LoadTranslation("ID_${item['APP_STATUS']}"); + } else { + $item['APP_STATUS_LABEL'] = $item['APP_STATUS']; + } + + // Merge in desired process data + // Handle situation where the process might not be in the system anymore + $item['APP_PRO_TITLE'] = $process ? $process->PRO_TITLE : ''; + + // Merge in desired user data + $item['USR_LASTNAME'] = $user ? $user->USR_LASTNAME : ''; + $item['USR_FIRSTNAME'] = $user ? $user->USR_FIRSTNAME : ''; + $item['USR_USERNAME'] = $user ? $user->USR_USERNAME : ''; + + //@todo: this section needs to use 'User Name Display Format', currently in the extJs is defined this + $item["APP_CURRENT_USER"] = $item["USR_LASTNAME"] . ' ' . $item["USR_FIRSTNAME"]; + + $item["APPDELCR_APP_TAS_TITLE"] = ''; + + $item["USRCR_USR_UID"] = $item["USR_UID"]; + $item["USRCR_USR_FIRSTNAME"] = $item["USR_FIRSTNAME"]; + $item["USRCR_USR_LASTNAME"] = $item["USR_LASTNAME"]; + $item["USRCR_USR_USERNAME"] = $item["USR_USERNAME"]; + $item["APP_OVERDUE_PERCENTAGE"] = ''; + + return $item; + }); + + // Remove any empty erroenous data + $results = $results->filter(); + + // Bundle into response array + $response = [ + // Fake totalCount to show pagination + 'totalCount' => $start + $limit + 1, + 'sql' => $query->toSql(), + 'bindings' => $query->getBindings(), + 'data' => $results->values()->toArray(), + ]; + + return $response; + } + +} diff --git a/workflow/engine/src/ProcessMaker/Model/Dynaform.php b/workflow/engine/src/ProcessMaker/Model/Dynaform.php new file mode 100644 index 000000000..4d270b2dc --- /dev/null +++ b/workflow/engine/src/ProcessMaker/Model/Dynaform.php @@ -0,0 +1,64 @@ +belongsTo(Process::class, 'PRO_UID', 'PRO_UID'); + } + + /** + * Get dynaforms by PRO_UID. + * @param string $proUid + * @return object + */ + public static function getByProUid($proUid) + { + return DB::table('DYNAFORM') + ->select() + ->where('DYNAFORM.PRO_UID', '=', $proUid) + ->get(); + } + + /** + * Get dynaform by DYN_UID. + * @param string $dynUid + * @return object + */ + public static function getByDynUid($dynUid) + { + return DB::table('DYNAFORM') + ->select() + ->where('DYNAFORM.DYN_UID', '=', $dynUid) + ->first(); + } + + /** + * Get dynaforms by PRO_UID except the DYN_UID specified in the second parameter. + * @param string $proUid + * @param string $dynUid + * @return object + */ + public static function getByProUidExceptDynUid($proUid, $dynUid) + { + return DB::table('DYNAFORM') + ->select() + ->where('DYNAFORM.PRO_UID', '=', $proUid) + ->where('DYNAFORM.DYN_UID', '!=', $dynUid) + ->get(); + } +} diff --git a/workflow/engine/src/ProcessMaker/Model/GroupUser.php b/workflow/engine/src/ProcessMaker/Model/GroupUser.php new file mode 100644 index 000000000..b20474e02 --- /dev/null +++ b/workflow/engine/src/ProcessMaker/Model/GroupUser.php @@ -0,0 +1,13 @@ +belongsTo(Application::class, 'APP_UID', 'APP_UID'); + } + + /** + * Return the process task this belongs to + */ + public function task() + { + return $this->belongsTo(Task::class, 'TAS_ID', 'TAS_ID'); + } + + /** + * Return the process this belongs to + */ + public function process() + { + return $this->belongsTo(Process::class, 'PRO_ID', 'PRO_ID'); + } + + /** + * Get count + * + * @param string $userUid + * @param array $filters + * + * @return array + */ + public static function doCount($userUid, $filters = []) + { + $list = new PropelListUnassigned(); + $result = $list->getCountList($userUid, $filters); + + return $result; + } + + /** + * Search data + * + * @param string $userUid + * @param array $filters + * + * @return array + */ + public static function loadList($userUid, $filters = []) + { + $list = new PropelListUnassigned(); + $result = $list->loadList($userUid, $filters); + + return $result; + } +} + diff --git a/workflow/engine/src/ProcessMaker/Model/Process.php b/workflow/engine/src/ProcessMaker/Model/Process.php index f131fb318..b32b92eb1 100644 --- a/workflow/engine/src/ProcessMaker/Model/Process.php +++ b/workflow/engine/src/ProcessMaker/Model/Process.php @@ -14,8 +14,29 @@ class Process extends Model { // Set our table name protected $table = 'PROCESS'; - // We do have a created at, but we don't store an updated at + // Our custom timestamp columns const CREATED_AT = 'PRO_CREATE_DATE'; - const UPDATED_AT = null; + const UPDATED_AT = 'PRO_UPDATE_DATE'; + /** + * Retrieve all applications that belong to this process + */ + public function applications() + { + return $this->hasMany(Application::class, 'PRO_ID', 'PRO_ID'); + } -} \ No newline at end of file + public function tasks() + { + return $this->hasMany(Task::class, 'PRO_UID', 'PRO_UID'); + } + + public function creator() + { + return $this->hasOne(User::class, 'PRO_CREATE_USER', 'USR_UID'); + } + + public function category() + { + return $this->hasOne(ProcessCategory::class, 'PRO_CATEGORY', 'CATEGORY_UID'); + } +} diff --git a/workflow/engine/src/ProcessMaker/Model/ProcessCategory.php b/workflow/engine/src/ProcessMaker/Model/ProcessCategory.php new file mode 100644 index 000000000..8ad9d705e --- /dev/null +++ b/workflow/engine/src/ProcessMaker/Model/ProcessCategory.php @@ -0,0 +1,19 @@ +belongsTo(Process::class, 'PRO_UID', 'PRO_UID'); + } + + public function delegations() + { + return $this->hasMany(Delegation::class, 'TAS_ID', 'TAS_ID'); + } +} diff --git a/workflow/engine/src/ProcessMaker/Model/TaskUser.php b/workflow/engine/src/ProcessMaker/Model/TaskUser.php new file mode 100644 index 000000000..67549792b --- /dev/null +++ b/workflow/engine/src/ProcessMaker/Model/TaskUser.php @@ -0,0 +1,12 @@ +hasMany(Delegation::class, 'USR_ID', 'USR_ID'); + } +} diff --git a/workflow/engine/src/ProcessMaker/Services/Api/Cases.php b/workflow/engine/src/ProcessMaker/Services/Api/Cases.php index 760671acf..9020dfbe7 100644 --- a/workflow/engine/src/ProcessMaker/Services/Api/Cases.php +++ b/workflow/engine/src/ProcessMaker/Services/Api/Cases.php @@ -1427,4 +1427,31 @@ class Cases extends Api return $response; } + /** + * Return information for sub process cases + * + * @url GET /:app_uid/sub-process-cases + * + * @param string $app_uid {@min 32}{@max 32} + * + * @return array + * @throws Exception + * + * @access protected + * @class AccessControl {@permission PM_CASES} + */ + public function doGetCaseSubProcess($app_uid) + { + try { + $case = new BmCases(); + $case->setFormatFieldNameInUppercase(false); + + $caseInfo = $case->getCaseInfoSubProcess($app_uid, $this->getUserId()); + $caseInfo = DateTime::convertUtcToIso8601($caseInfo, $this->arrayFieldIso8601); + + return $caseInfo; + } catch (Exception $e) { + throw new RestException(Api::STAT_APP_EXCEPTION, $e->getMessage()); + } + } } diff --git a/workflow/engine/src/ProcessMaker/Services/Api/Light.php b/workflow/engine/src/ProcessMaker/Services/Api/Light.php index 9f4233246..a1f6a80a3 100644 --- a/workflow/engine/src/ProcessMaker/Services/Api/Light.php +++ b/workflow/engine/src/ProcessMaker/Services/Api/Light.php @@ -1038,6 +1038,7 @@ class Light extends Api } $userUid = $this->getUserId(); + //@todo Find a better way to define session variables $_SESSION["APPLICATION"] = $app_uid; $_SESSION["PROCESS"] = $pro_uid; //$_SESSION["TASK"] = ""; @@ -2009,6 +2010,7 @@ class Light extends Api if ($alreadyRouted) { throw (new RestException(Api::STAT_APP_EXCEPTION, G::LoadTranslation('ID_CASE_DELEGATION_ALREADY_CLOSED'))); } + //@todo Find a better way to define session variables $_SESSION["APPLICATION"] = $app_uid; $_SESSION["PROCESS"] = $pro_uid; $_SESSION["INDEX"] = $app_index; diff --git a/workflow/engine/src/ProcessMaker/Util/DateTime.php b/workflow/engine/src/ProcessMaker/Util/DateTime.php index 26dba185f..d30d35a7e 100644 --- a/workflow/engine/src/ProcessMaker/Util/DateTime.php +++ b/workflow/engine/src/ProcessMaker/Util/DateTime.php @@ -7,6 +7,7 @@ class DateTime const REGEXPDATE = '[1-9]\d{3}\-(?:0[1-9]|1[0-2])\-(?:0[1-9]|[12][0-9]|3[01])'; const REGEXPTIME = '(?:[0-1]\d|2[0-3])\:[0-5]\d\:[0-5]\d'; + const REGEX_IS_DATE = '/^([1-9]\d{3})\-(0[1-9]|1[0-2])\-(0[1-9]|[12][0-9]|3[01])(?:\s([0-1]\d|2[0-3])\:([0-5]\d)\:([0-5]\d))?$/'; /** * Get Time Zone Offset by Time Zone ID diff --git a/workflow/engine/src/ProcessMaker/Util/FixReferencePath.php b/workflow/engine/src/ProcessMaker/Util/FixReferencePath.php index 705f20afc..48ebe7cb2 100644 --- a/workflow/engine/src/ProcessMaker/Util/FixReferencePath.php +++ b/workflow/engine/src/ProcessMaker/Util/FixReferencePath.php @@ -2,17 +2,18 @@ namespace ProcessMaker\Util; -use Configurations; -use Criteria; -use ResultSet; -use FieldsPeer; -use ReportTablePeer; -use CaseConsolidatedCorePeer; -use ConsolidatedCases; -use AdditionalTablesPeer; -use PmTable; -use ReportVarPeer; use AdditionalTables; +use AdditionalTablesPeer; +use CaseConsolidatedCorePeer; +use Configurations; +use ConsolidatedCases; +use Criteria; +use FieldsPeer; +use PmTable; +use ProcessMaker\Core\System; +use ReportTablePeer; +use ReportVarPeer; +use ResultSet; use stdClass; /** @@ -73,6 +74,7 @@ class FixReferencePath * @param string $directory * @param string $pathData * @return void + * @see workflow/engine/classes/WorkspaceTools.php WorkspaceTools->fixReferencePathFiles() */ public function runProcess($directory, $pathData) { @@ -81,8 +83,8 @@ class FixReferencePath //task, it is removed at the end of the method. $_SERVER["REQUEST_URI"] = ""; if (!defined("SYS_SKIN")) { - $conf = new Configurations(); - define("SYS_SKIN", $conf->getConfiguration('SKIN_CRON', '')); + $config = System::getSystemConfiguration(); + define("SYS_SKIN", $config['default_skin']); } $criteria = new Criteria("workflow"); diff --git a/workflow/engine/src/ProcessMaker/Util/PhpShorthandByte.php b/workflow/engine/src/ProcessMaker/Util/PhpShorthandByte.php new file mode 100644 index 000000000..6207298be --- /dev/null +++ b/workflow/engine/src/ProcessMaker/Util/PhpShorthandByte.php @@ -0,0 +1,82 @@ +units = ['K', 'M', 'G']; + $this->terminal = "bytes"; + } + + /** + * Convert value string to bytes, for directives php.ini + * + * @param string $value + * @return integer + * + * @see ProcessMaker\BusinessModel\InputDocument->getMaxFileSize() + * @link http://php.net/manual/en/faq.using.php#faq.using.shorthandbytes + */ + public function valueToBytes($value) + { + foreach ($this->units as $i => $unit) { + $number = $this->getNumberValue($value, $unit); + if ($number !== null) { + $result = $number * (1024 ** ($i + 1)); + return $result; + } + } + return intval($value); + } + + /** + * Get number value and validate expresion. + * Valid expresion is: [number][unit] + * + * @param string $string + * @param string $unit + * @return integer|null + * + * @see ProcessMaker\Util\PhpShorthandByte->valueToBytes() + * @link http://php.net/manual/en/faq.using.php#faq.using.shorthandbytes + */ + public function getNumberValue($string, $unit) + { + $string = preg_replace('/\s+/', '', $string); + $isCorrect = preg_match("/\d+{$unit}/", $string); + if ($isCorrect === 1) { + $result = rtrim($string, $unit); + return intval($result); + } + return null; + } + + /** + * Get format bytes. + * + * @param string $value + * @return string + */ + public function getFormatBytes($value) + { + foreach ($this->units as $i => $unit) { + $number = $this->getNumberValue($value, $unit); + if ($number !== null) { + return $number . " " . $unit . $this->terminal; + } + } + return $value; + } +} diff --git a/workflow/engine/src/ProcessMaker/Util/helpers.php b/workflow/engine/src/ProcessMaker/Util/helpers.php index 9a44ab50b..684569b0f 100644 --- a/workflow/engine/src/ProcessMaker/Util/helpers.php +++ b/workflow/engine/src/ProcessMaker/Util/helpers.php @@ -400,6 +400,81 @@ function verifyCsrfToken($request) } } +/** + * Get the difference between to arrays + * If the element is an array we will to keep the value from $array1 + * If the element is an object we will to keep the value from $array1 + * + * @param array $array1 + * @param array $array2 + * + * @return array + */ +function getDiffBetweenModifiedVariables(array $array1, array $array2) +{ + $difference = []; + foreach ($array1 as $key => $value) { + if (is_array($value)) { + if ($value !== $array2[$key]) { + $difference[$key] = $value; + } + } elseif (is_object($value)) { + // When using ===, it means object variables are identical and they refer to the same instance of the same class. + if ($value != $array2[$key]) { + $difference[$key] = $value; + } + } elseif (!isset($array2[$key]) || $array2[$key] != $value) { + $difference[$key] = $value; + } + } + + return $difference; +} + +/** + * Replace all supported variables prefixes to the prefix sent + * + * @param string $outDocFilename + * @param string $prefix + * + * @return string + * + * @see cases_Step.php + * @see \ProcessMaker\BusinessModel\Cases\OutputDocument::addCasesOutputDocument() + * @link https://wiki.processmaker.com/3.2/Triggers#Typing_rules_for_Case_Variables + */ +function replacePrefixes($outDocFilename, $prefix = '@=') +{ + $outDocFile = str_replace(['@@', '@#', '@=', '@%', '@?', '@$', '@&', '@Q', '@q', '@!'], $prefix, $outDocFilename); + + return $outDocFile; +} + +/** + * Encoding header filename used in Content-Disposition + * + * @param string $fileName + * @param string $replacement + * + * @return string + * + * @see cases_Step.php + * @see \ProcessMaker\BusinessModel\Cases\OutputDocument::addCasesOutputDocument() + */ +function fixContentDispositionFilename($fileName, $replacement = '_') +{ + //(double quote) has to be removed + //(forward slash) has to replaced by underscore + //(backslash) has to replaced by underscore + $default = [ + '/[\"]/' => '', + '/[\\|\/]/' => $replacement, + '/\\\\/' => $replacement + ]; + + return preg_replace(array_keys($default), array_values($default), $fileName); +} + /** * Get the current user CSRF token. * @@ -410,6 +485,33 @@ function csrfToken() return isset($_SESSION['USR_CSRF_TOKEN']) ? $_SESSION['USR_CSRF_TOKEN'] : ''; } +/** + * Check if a string is a valid HTML code + * + * @param string $string + * + * @return bool + * + * @see G::replaceDataField() + */ +function stringIsValidHtml($string) +{ + // To validate we use the DOMDocument class + $doc = new DOMDocument('1.0', 'UTF-8'); + + // Clean previous errors + libxml_clear_errors(); + + // This line have to be silenced because if the string is not an HTML a Warning is displayed + @$doc->loadHTML($string); + + // Get last error parsing the HTML + $libXmlError = libxml_get_last_error(); + + // If the attribute "textContent" is empty or exists libxml errors, is not a valid HTML + return $doc->textContent !== '' && empty($libXmlError); +} + // Methods deleted in PHP 7.x, added in this file in order to keep compatibility with old libraries included/used in ProcessMaker if (!function_exists('set_magic_quotes_runtime')) { function set_magic_quotes_runtime($value) { diff --git a/workflow/engine/src/ProcessMaker/Validation/ValidationUploadedFiles.php b/workflow/engine/src/ProcessMaker/Validation/ValidationUploadedFiles.php index 42b11989b..d354f21fa 100644 --- a/workflow/engine/src/ProcessMaker/Validation/ValidationUploadedFiles.php +++ b/workflow/engine/src/ProcessMaker/Validation/ValidationUploadedFiles.php @@ -8,6 +8,7 @@ use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Facades\Cache; use ProcessMaker\Core\System; use ProcessMaker\Services\OAuth2\Server; +use ProcessMaker\Util\PhpShorthandByte; use Symfony\Component\HttpFoundation\File\File; class ValidationUploadedFiles @@ -169,6 +170,8 @@ class ValidationUploadedFiles * File upload validation. * * @return $this + * + * @see workflow/public_html/sysGeneric.php */ public function runRulesToAllUploadedFiles() { @@ -177,6 +180,12 @@ class ValidationUploadedFiles return; } $this->fails = []; + + $validator = $this->runRulesForFileEmpty(); + if ($validator->fails()) { + $this->fails[] = $validator; + } + foreach ($files as $file) { $data = (object) $file; if (!is_array($data->name) || !is_array($data->tmp_name)) { @@ -207,16 +216,77 @@ class ValidationUploadedFiles } } } + return $this; } + /** + * Run rules if files is empty. + * + * @see ProcessMaker\Validation\ValidationUploadedFiles->runRulesToAllUploadedFiles() + * @see Luracast\Restler\Format\UploadFormat->decode() + */ + public function runRulesForFileEmpty() + { + $validator = new Validator(); + + //rule: validate $_SERVER['CONTENT_LENGTH'] + $rule = $validator->addRule(); + $rule->validate(null, function($file) use ($rule) { + //according to the acceptance criteria the information is always shown in MBytes + $phpShorthandByte = new PhpShorthandByte(); + $postMaxSize = ini_get("post_max_size"); + $postMaxSizeBytes = $phpShorthandByte->valueToBytes($postMaxSize); + $uploadMaxFileSize = ini_get("upload_max_filesize"); + $uploadMaxFileSizeBytes = $phpShorthandByte->valueToBytes($uploadMaxFileSize); + + if ($postMaxSizeBytes < $uploadMaxFileSizeBytes) { + $uploadMaxFileSize = $postMaxSize; + $uploadMaxFileSizeBytes = $postMaxSizeBytes; + } + //according to the acceptance criteria the information is always shown in MBytes + $uploadMaxFileSizeMBytes = $uploadMaxFileSizeBytes / (1024 ** 2); //conversion constant + + $message = G::LoadTranslation('ID_THE_FILE_SIZE_IS_BIGGER_THAN_THE_MAXIMUM_ALLOWED', [$uploadMaxFileSizeMBytes]); + $rule->message($message); + /** + * If you can, you may want to set post_max_size to a low value (say 1M) to make + * testing easier. First test to see how your script behaves. Try uploading a file + * that is larger than post_max_size. If you do you will get a message like this + * in your error log: + * + * [09-Jun-2010 19:28:01] PHP Warning: POST Content-Length of 30980857 bytes exceeds + * the limit of 2097152 bytes in Unknown on line 0 + * + * This makes the script is not completed. + * + * Solving the problem: + * The PHP documentation http://php.net/manual/en/ini.core.php#ini.post-max-size + * provides a hack to solve this problem: + * + * If the size of post data is greater than post_max_size, the $_POST and $_FILES + * superglobals are empty. + */ + if ($_SERVER['REQUEST_METHOD'] === 'POST' && empty($_POST) && empty($_FILES) && $_SERVER['CONTENT_LENGTH'] > 0) { + return true; + } + return false; + }) + ->status(400) + ->log(function($rule) { + Bootstrap::registerMonologPhpUploadExecution('phpUpload', 400, $rule->getMessage(), ""); + }); + + return $validator->validate(); + } + /** * Get the first error and call the argument function. * * @param function $callback * @return $this */ - public function dispach($callback) + public function dispatch($callback) { if (!empty($this->fails[0])) { if (!empty($callback) && is_callable($callback)) { diff --git a/workflow/engine/templates/cases/casesList.js b/workflow/engine/templates/cases/casesList.js index f44e7c2f6..398b6e812 100644 --- a/workflow/engine/templates/cases/casesList.js +++ b/workflow/engine/templates/cases/casesList.js @@ -25,6 +25,9 @@ var textJump; var ids = ''; var winReassignInCasesList; var casesNewTab; +var mask; +var loadingMessage; +var timeoutMark = false; function formatAMPM(date, initVal, calendarDate) { @@ -309,6 +312,7 @@ function pauseCase(date){ buttons: [{ text: _('ID_OK'), handler: function(){ + this.setDisabled(true); if (Ext.getCmp('noteReason').getValue() != '') { var noteReasonTxt = _('ID_CASE_PAUSE_LABEL_NOTE') + ' ' + Ext.getCmp('noteReason').getValue(); } else { @@ -854,25 +858,30 @@ Ext.onReady ( function() { this.setBaseParam( "openApplicationUid", (__OPEN_APPLICATION_UID__ !== null)? __OPEN_APPLICATION_UID__ : "" ); + timeoutMark = false; }, load: function(response){ - - if (response.reader.jsonData.result === false) { - PMExt.notify('ERROR', response.reader.jsonData.message); - //PMExt.error + if (action === "search" && loadingMessage) { + loadingMessage.hide(); + timeoutMark = true; } }, - exception: function(dp, type, action, options, response, arg) { - responseObject = Ext.util.JSON.decode(response.responseText); - if (typeof(responseObject.error) != 'undefined') { - Ext.Msg.show({ - title: _('ID_ERROR'), - msg: responseObject.error, - fn: function(){parent.parent.location = '../login/login';}, - animEl: 'elId', - icon: Ext.MessageBox.ERROR, - buttons: Ext.MessageBox.OK - }); + exception: function(dp, type, action, options, response, arg) { + if (response && typeof (response.status) !== 'undefined') { + showErrorMessage(response.status); + timeoutMark = true; + } else { + responseObject = Ext.util.JSON.decode(response.responseText); + if (typeof(responseObject.error) !== 'undefined') { + Ext.Msg.show({ + title: _('ID_ERROR'), + msg: responseObject.error, + fn: function(){parent.parent.location = '../login/login';}, + animEl: 'elId', + icon: Ext.MessageBox.ERROR, + buttons: Ext.MessageBox.OK + }); + } } } } @@ -1063,7 +1072,6 @@ Ext.onReady ( function() { handler: function(){ storeCases.setBaseParam('process', ''); suggestProcess.setValue(''); - doSearch(); } }; @@ -1322,7 +1330,6 @@ Ext.onReady ( function() { storeCases.setBaseParam( 'user', filterUser); storeCases.setBaseParam( 'start', 0); storeCases.setBaseParam( 'limit', pageSize); - doSearch(); } } }); @@ -1347,6 +1354,72 @@ Ext.onReady ( function() { //cls: 'x-form-toolbar-standardButton', handler: doSearch }); + + /** + * Show loading Dialog + */ + function showLoadingDialog() { + mask.hide(); + var commonSettings = { + title: _('ID_SEARCHING'), + width: 700, + wait: true, + waitConfig: {interval:200} + }; + + loadingMessage = Ext.Msg.show(commonSettings); + setTimeout( + function() { + if (!timeoutMark) { + loadingMessage.hide(); + commonSettings['msg'] = _('ID_SEARCHING_CANCEL_MESSAGE'), + commonSettings['buttons'] = Ext.Msg.CANCEL, + commonSettings['fn'] = function (btn, text) { + if (btn === 'cancel') { + proxyCasesList.getConnection().abort(); + }; + } + loadingMessage = Ext.Msg.show(commonSettings); + timeoutMark = false; + } + }, 2000); + }; + /** + * Show the error code. + * @param {*} errorCode + */ + function showErrorMessage(errorCode) { + var message; + switch (errorCode) { + case 408: + case 504: + message = _('ID_SEARCHING_TIME_OUT'); + break; + case 0: + case -1: + message = _('ID_SEARCHING_UNEXPECTED_ERROR_DEFAULT'); + break; + default: + message = _('ID_SEARCHING_UNEXPECTED_ERROR', [errorCode]); + } + + Ext.Msg.show({ + title:_('ID_ERROR'), + msg: message, + animEl: 'elId', + icon: Ext.MessageBox.ERROR, + buttons: Ext.MessageBox.OK + }); + }; + function showTimeoutMessage() { + Ext.Msg.show({ + title:_('ID_ERROR'), + msg: _('ID_SEARCHING_TIME_OUT'), + animEl: 'elId', + icon: Ext.MessageBox.ERROR, + buttons: Ext.MessageBox.OK + }); + }; function doSearch(){ //var viewText = Ext.getCmp('casesGrid').getView(); @@ -1358,14 +1431,16 @@ Ext.onReady ( function() { storeCases.setBaseParam('dateTo', dateTo.getValue()); storeCases.setBaseParam( 'search', searchText); storeCases.load({params:{ start : 0 , limit : pageSize }}); - } + if ( action === 'search' ){ + showLoadingDialog(); + } + }; var resetSearchButton = { text:'X', ctCls:"pm_search_x_button_des", handler: function(){ textSearch.setValue(''); - doSearch(); } } @@ -1375,7 +1450,6 @@ Ext.onReady ( function() { handler: function(){ suggestUser.setValue(''); storeCases.setBaseParam('user', ''); - doSearch(); } } @@ -2218,7 +2292,7 @@ Ext.onReady ( function() { emptyMsg: _('ID_DISPLAY_EMPTY') }) } - var mask = new Ext.LoadMask(Ext.getBody(), {msg: _('ID_LOADING')}); + mask = new Ext.LoadMask(Ext.getBody(), {msg: _('ID_LOADING')}); // create the editor grid grid = new Ext.grid.GridPanel({ region: 'center', @@ -2226,7 +2300,6 @@ Ext.onReady ( function() { store: storeCases, cm: cm, loadMask: mask, - sm: new Ext.grid.RowSelectionModel({ selectSingle: false, listeners:{ diff --git a/workflow/engine/templates/cases/casesListSetup.js b/workflow/engine/templates/cases/casesListSetup.js index e90854240..d5f3251f4 100644 --- a/workflow/engine/templates/cases/casesListSetup.js +++ b/workflow/engine/templates/cases/casesListSetup.js @@ -64,7 +64,7 @@ Ext.onReady(function () { success: function (response, opts) { - var dataResponse = eval("(" + response.responseText + ")"); //json + var dataResponse = Ext.util.JSON.decode(response.responseText); switch (option) { case "FIELD_SET": @@ -85,8 +85,11 @@ Ext.onReady(function () { break; case "FIELD_SAVE": configDefaultResponseText = response.responseText; - Ext.Msg.alert(_("ID_INFO"), _("ID_SAVED")); - location.reload(true); + var windowAlert = Ext.Msg.alert(_("ID_INFO"), _("ID_SAVED")); + fieldSet(dataResponse); + setTimeout(function () { + windowAlert.getDialog().close(); + }, 500); break; } }, @@ -150,75 +153,55 @@ Ext.onReady(function () { {name: 'align', mapping : 'align'} ]; - //Dropdown to select the PMTable - var PmTableStore = new Ext.data.JsonStore({ - root : 'data', - url : 'proxyPMTablesList', - totalProperty : 'totalCount', - idProperty : 'gridIndex', - remoteSort : false, //true, - autoLoad : false, - fields : [ - 'ADD_TAB_UID', 'ADD_TAB_NAME' - ], - listeners : {load: function() { - tabs.setActiveTab(tabIndex); - }} - }); - - // create the Data Store to list PMTables in the dropdown - var pmTablesDropdown = new Ext.form.ComboBox ({ - width : '180', - xtype : 'combo', - emptyText: _("ID_EMPTY_PMTABLE"), - displayField : 'ADD_TAB_NAME', - valueField : 'ADD_TAB_UID', - triggerAction: 'all', - store : PmTableStore, - listeners: { - 'select': function() { - var tableUid = this.value; - Ext.Ajax.request({ - url: 'proxyPMTablesFieldList', - success: function(response) { - var dataResponse = Ext.util.JSON.decode(response.responseText); - var rec = Ext.data.Record.create(pmFields); - //alert(firstGrid.store); - var index; - var record; - var count = firstGrid.store.getTotalCount(); - - // removing all the PM Table fields from the first grid - do { - index = firstGrid.store.find('fieldType','PM Table'); - record = firstGrid.store.getAt(index); - if (index>=0) { - firstGrid.store.remove(record); - } - } while (index>=0); - - // removing all the PM Table fields from the second grid - do { - index = secondGrid.store.find('fieldType','PM Table'); - record = secondGrid.store.getAt(index); - if (index>=0) { - secondGrid.store.remove(record); - } - } while (index>=0); - - for (var i = 0; i <= dataResponse.data.length-1; i++) { - var d = new rec( dataResponse.data[i] ); - firstGrid.store.add(d); + //Dropdown to select the PMTable + var PmTableStore = new Ext.data.JsonStore({ + root: 'data', + url: 'proxyPMTablesList', + totalProperty: 'totalCount', + idProperty: 'gridIndex', + remoteSort: false, //true, + autoLoad: false, + fields: [ + 'ADD_TAB_UID', 'ADD_TAB_NAME' + ], + listeners: { + load: function () { + tabs.setActiveTab(tabIndex); } - firstGrid.store.commitChanges(); - }, - failure: function(){}, - params: {xaction: 'getFieldsFromPMTable', table: tableUid } - }); + } + }); - } - } - }); + // create the Data Store to list PMTables in the dropdown + var pmTablesDropdown = new Ext.form.ComboBox({ + width: '180', + xtype: 'combo', + emptyText: _("ID_EMPTY_PMTABLE"), + displayField: 'ADD_TAB_NAME', + valueField: 'ADD_TAB_UID', + triggerAction: 'all', + store: PmTableStore, + listeners: { + focus: function(){ + PmTableStore.load(); + }, + 'select': function () { + var tableUid = this.value; + Ext.Ajax.request({ + url: 'proxyPMTablesFieldList', + params: { + xaction: 'FIELD_SET', + action: currentAction, + table: tableUid + }, + success: function (response) { + var dataResponse = Ext.util.JSON.decode(response.responseText); + fieldSet(dataResponse); + }, + failure: function () {} + }); + } + } + }); // COMPONENT DEPRECATED remove it in the next revision of the enterprise plugin // create the Dropdown for rows per page @@ -501,6 +484,20 @@ Ext.onReady(function () { height : screen.height-245, layout : 'hbox', layoutConfig : {align : 'stretch'}, + listeners: { + render: function (target) { + var el; + if (target.container && target.container.dom) { + el = target.container.dom; + el.style.cssText = 'overflow:hidden;position:absolute;top:28px;bottom:0px;left:0px;right:0px;'; + target.setHeight(el.clientHeight); + Ext.EventManager.onWindowResize(function () { + mainPanel.setHeight(el.clientHeight); + mainPanel.doLayout(); + }); + } + } + }, tbar : new Ext.Toolbar({ items: [ _("ID_PM_TABLE"), @@ -573,7 +570,7 @@ Ext.onReady(function () { text: _("ID_RESET"), handler: function () { - var dataResponse = eval("(" + configDefaultResponseText + ")"); //json + var dataResponse = Ext.util.JSON.decode(configDefaultResponseText); fieldSet(dataResponse); } diff --git a/workflow/engine/templates/cases/main.js b/workflow/engine/templates/cases/main.js index d43e42d00..c31bf1598 100644 --- a/workflow/engine/templates/cases/main.js +++ b/workflow/engine/templates/cases/main.js @@ -1,16 +1,18 @@ -var PANEL_EAST_OPEN = false; -var centerPanel; -var setFlag; -var flagRefresh = true; -var debugVarTpl = new Ext.Template('{value}'); -var detailsText = ''; -var debugTriggersDetailTpl = new Ext.Template('
{code}
'); -var propStore; -var triggerStore; -var result; -var _action = ''; +var PANEL_EAST_OPEN = false, + centerPanel, + setFlag, + flagRefresh = true, + debugVarTpl = new Ext.Template('{value}'), + detailsText = '', + debugTriggersDetailTpl = new Ext.Template('
{code}
'), + propStore, + triggerStore, + result, + _action = '', //@var treeMenuItemsLoaded -> added to flag the "treeMenuItems" tree, to ensure that its onload event is executed just once -var treeMenuItemsLoaded = false; + treeMenuItemsLoaded = false, + loader, + _BROWSER; debugVarTpl.compile(); debugTriggersDetailTpl.compile(); @@ -97,34 +99,56 @@ Ext.onReady(function(){ 'render': function(tp){} } }); - - var loader = treeMenuItems.getLoader(); - loader.on("load", function() { - // it was added since the feature to reload a specific node of tree is now working - if (! treeMenuItemsLoaded) { // this section of code should be executed once - document.getElementById('casesSubFrame').src = defaultOption; - - // check if a case was open directly - if (defaultOption.indexOf('open') > -1) { - //if it is, then update cases trees - updateCasesTree(); - } - - if(_nodeId !== ''){ - treePanel1 = Ext.getCmp('tree-panel'); - if(treePanel1) - node = treePanel1.getNodeById(_nodeId); - if(node) { - node.select(); - if (_nodeId === 'CASES_START_CASE') { - updateCasesTree(); - } + /** + * Gets the user client browser and its version + * @return (object) + */ + function getBrowserClient() { + var browsers = ["opera", "msie", "firefox", "opera", "safari", "trident"], + infoBrowser = navigator.userAgent.toLowerCase(), + versionBrowser, + currentBrowser = ""; + for (var i = 0; i < browsers.length; i++) { + if ((currentBrowser === "") && (infoBrowser.indexOf(browsers[i]) !== -1)) { + currentBrowser = browsers[i]; + versionBrowser = String(parseFloat(infoBrowser.substr(infoBrowser.indexOf(browsers[i]) + browsers[i].length + 1))); + return {name: currentBrowser, browser: currentBrowser, version: versionBrowser} + } } - } - - treeMenuItemsLoaded = true; + return false; } - }); + _BROWSER = getBrowserClient(); + loader = treeMenuItems.getLoader(); + loader.on("load", function () { + var treePanel1, + node; + // it was added since the feature to reload a specific node of tree is now working + if (!treeMenuItemsLoaded) { // this section of code should be executed once + if ((_BROWSER.name === "msie" || _BROWSER.name === "trident") && openCaseIE) { + parent.window.location.href = defaultOption; + } else { + document.getElementById('casesSubFrame').src = defaultOption; + // check if a case was open directly + if (defaultOption.indexOf('open') > -1) { + //if it is, then update cases trees + updateCasesTree(); + } + if (_nodeId !== '') { + treePanel1 = Ext.getCmp('tree-panel'); + if (treePanel1) { + node = treePanel1.getNodeById(_nodeId); + } + if (node) { + node.select(); + if (_nodeId === 'CASES_START_CASE') { + updateCasesTree(); + } + } + } + } + treeMenuItemsLoaded = true; + } + }); // set the root node var root = new Ext.tree.AsyncTreeNode({ @@ -649,7 +673,7 @@ Ext.app.menuLoader = Ext.extend(Ext.ux.tree.XmlTreeLoader, { //} }else if(attr.title){ attr.text = Ext.util.Format.htmlDecode(attr.title); - + if( attr.cases_count ) attr.text += ' ()'; diff --git a/workflow/engine/templates/cases/open.js b/workflow/engine/templates/cases/open.js index 8b8feb00f..02bf72736 100644 --- a/workflow/engine/templates/cases/open.js +++ b/workflow/engine/templates/cases/open.js @@ -1,11 +1,14 @@ -var Actions = {}; -var showCaseNavigatorPanel; -var hideCaseNavigatorPanel; -var informationMenu; -var caseMenuOpen = false; -var menuSelectedTitle = []; -var _ENV_CURRENT_DATE; -var winTree; +var Actions = {}, + hideCaseNavigatorPanel, + informationMenu, + caseMenuOpen = false, + menuSelectedTitle = [], + _ENV_CURRENT_DATE, + winTree, + buttonCancel, + buttonClaimCase, + navPanelBottom, + navPanel; historyGridListChangeLogGlobal = {}; historyGridListChangeLogGlobal.idHistory = ''; @@ -32,13 +35,14 @@ function formatAMPM(date, initVal) { return strTime; }; -function isBrowserIE(){ - if ( (navigator.userAgent.indexOf("MSIE")!=-1) || (navigator.userAgent.indexOf("Trident")!=-1) ){ - return true; - } else { - return false; - } -}; +/** + * Verify if the browser is Internet Explorer + * @return {boolean} + */ +function isBrowserIE() { + var browserAgent = navigator.userAgent.toLowerCase(); + return (browserAgent.indexOf("msie") !== -1) || (browserAgent.indexOf("trident") !== -1); +} Ext.onReady(function(){ openToRevisePanel = function() { @@ -157,7 +161,7 @@ Ext.onReady(function(){ tb.add(menu); } } - + var olink = document.location.href; if(olink.search("gmail") != -1){ Ext.getCmp('stepsMenu').hide(); @@ -229,7 +233,7 @@ Ext.onReady(function(){ if (node.attributes.url) { //Set load event - if (navigator.userAgent.toLowerCase().indexOf("msie") != -1) { + if (navigator.userAgent.toLowerCase().indexOf("msie") !== -1 || navigator.userAgent.toLowerCase().indexOf("trident") !== -1) { document.getElementById("openCaseFrame").onreadystatechange = function () { if (document.getElementById("openCaseFrame").readyState == "complete") { @@ -350,109 +354,218 @@ Ext.onReady(function(){ setNode(idfirstform); } - var navPanelWest = { - id: 'navPanelWest', - region: 'west', - xtype:'panel', - width: 250, - height: 500, - maxSize: 400, - split: true, - collapsible: false, - margins: '0 0 0 0', - items:[casesStepTree] - } - - var fnChangeStatus =function(){ - alert('loaded'); - } - - var screenWidth = (PMExt.getBrowser().screen.width-140).toString() + 'px'; - - var navPanelCenter = { - id: 'navPanelCenter', - region: 'center', layout:'fit',forceLayout: true, - xtype:'panel', - items:[{ - xtype:"tabpanel", - id: 'caseTabPanel', - deferredRender:false, - defaults:{autoScroll: true}, - defaultType:"iframepanel", - activeTab: 0, - enableTabScroll: true, - //defaults: Ext.apply({}, Ext.isGecko? {style:{position:'absolute'},hideMode:'visibility'}:false), - - items:[{ - id: 'casesTab', - title: _('ID_CASE') +' ' + _APP_NUM, - frameConfig:{name:'openCaseFrame', id:'openCaseFrame'}, - defaultSrc : uri, - loadMask:{msg: _('ID_LOADING_GRID') }, - bodyStyle:{height: (PMExt.getBrowser().screen.height-60) + 'px', overflow:'hidden'}, - width:screenWidth - - } - ], - listeners: { - tabchange: function(panel){ - panel.ownerCt.doLayout(); - }, - render : function(panel){ - Ext.each([this.el, this[this.collapseEl]] , - function( elm ) { - elm.setVisibilityMode(Ext.Element.VISIBILITY).originalDisplay ='visible'; - }); - } - } - }] - }; - - var navPanel = { - id: 'navPanel', - region: 'center', - layout: 'border', - items:[navPanelWest, navPanelCenter], - tbar:[{ - id: 'stepsMenu', - text: '  '+_('ID_STEPS'), - pressed: false, - enableToggle:true, - tooltip: { - title: _('ID_CASES_STEPS'), - text:_('ID_SHOW_HIDE_CASES_STEPS') - }, - iconCls: 'ICON_STEPS', - toggleHandler: togglePreview, - disabled: true - }, { - id: 'informationMenu', - text: _('ID_INFORMATION'), - menu: [] - }, { - id: 'actionMenu', - text: _('ID_ACTIONS'), - menu: [] - }, { - id: 'caseNotes', - pressed: false, - enableToggle:true, - text: '  '+_('ID_CASES_NOTES'), - iconCls: 'button_menu_ext ICON_CASES_NOTES', - tooltip: { - title: _('ID_CASES_NOTES'), - text:_('ID_SHOW_CASES_NOTES') - }, - toggleHandler:function(btn, pressed){ - if(pressed){ - openCaseNotesWindow(); - }else{ - closeCaseNotesWindow(); - } + var navPanelWest = { + id: 'navPanelWest', + region: 'west', + xtype:'panel', + width: 250, + height: 500, + maxSize: 400, + split: true, + collapsible: false, + margins: '0 0 0 0', + items:[casesStepTree] } - }] - } + var fnChangeStatus =function(){ + alert('loaded'); + } + + var screenWidth = (PMExt.getBrowser().screen.width-140).toString() + 'px'; + + var navPanelCenter = { + id: 'navPanelCenter', + region: 'center', layout:'fit',forceLayout: true, + xtype:'panel', + items:[{ + xtype:"tabpanel", + id: 'caseTabPanel', + deferredRender:false, + defaults:{autoScroll: true}, + defaultType:"iframepanel", + activeTab: 0, + enableTabScroll: true, + //defaults: Ext.apply({}, Ext.isGecko? {style:{position:'absolute'},hideMode:'visibility'}:false), + + items:[{ + id: 'casesTab', + title: _('ID_CASE') +' ' + _APP_NUM, + frameConfig:{name:'openCaseFrame', id:'openCaseFrame'}, + defaultSrc : uri, + loadMask:{msg: _('ID_LOADING_GRID') }, + bodyStyle:{height: (PMExt.getBrowser().screen.height-60) + 'px', overflow:'hidden'}, + width:screenWidth + + } + ], + listeners: { + tabchange: function(panel){ + panel.ownerCt.doLayout(); + }, + render : function(panel){ + Ext.each([this.el, this[this.collapseEl]] , + function( elm ) { + elm.setVisibilityMode(Ext.Element.VISIBILITY).originalDisplay ='visible'; + }); + } + } + }] + }; + + buttonCancel = new Ext.Button({ + buttonAlign: 'center', + text: 'Cancel', + handler: redirectHistory, + cls: 'cancelSummary', + width: '100px', + flex: 1, + style: "height:36px" + }); + + buttonClaimCase = new Ext.Button({ + buttonAlign: 'center', + ui: 'round', + text: 'Claim this case', + handler: claimCase, + cls: 'claimCaseSummary', + width: '120px', + flex: 1, + style: "height:36px" + }); + + navPanelBottom = { + id: 'navPanelBottom', + name: 'navPanelBottom', + cls: 'navPanelBottom', + region: 'south', + layout: 'column', + dock: 'bottom', + border: false, + margin: '0 0 0 0', + split: false, + collapsible: false, + hidden: false, + buttonAlign: 'center', + buttonHeight: 200, + buttons: [buttonCancel, buttonClaimCase] + }; + + /** + * Claim the case. + */ + function claimCase() { + Ext.Ajax.request({ + url: 'cases_CatchExecute', + success: function (response, opts) { + Ext.Ajax.request({ + url: 'ajaxListener', + params: {action : 'steps'}, + success: function (response, opts) { + Ext.getCmp('navPanelBottom').hide(); + Ext.getCmp('navPanel').doLayout(); + //Reload frame pmDynaform + if (isBrowserIE()) { + document.getElementById('openCaseFrame').contentWindow.location.reload(true); + } else { + Ext.getCmp('navPanelCenter').getUpdater().getEl().update(); + } + } + }); + } + }); + } + + /** + * Redirect to unassigned inbox. + */ + function redirectHistory() { + if (isBrowserIE()) { + if (top.opener) { + //Is open the claim case in another tab + top.opener.location.reload(); + top.close(); + } else { + //When isIE with ux skin is not open another tab + javascript:history.back(); + } + } else { + javascript:history.back(); + } + } + + navPanel = { + id: 'navPanel', + region: 'center', + layout: 'border', + items: [navPanelWest, navPanelCenter], + tbar: [{ + id: 'stepsMenu', + text: '  ' + _('ID_STEPS'), + pressed: false, + enableToggle: true, + tooltip: { + title: _('ID_CASES_STEPS'), + text: _('ID_SHOW_HIDE_CASES_STEPS') + }, + iconCls: 'ICON_STEPS', + toggleHandler: togglePreview, + disabled: true + }, { + id: 'informationMenu', + text: _('ID_INFORMATION'), + menu: [] + }, { + id: 'actionMenu', + text: _('ID_ACTIONS'), + menu: [] + }, { + id: 'caseNotes', + pressed: false, + enableToggle: true, + text: '  ' + _('ID_CASES_NOTES'), + iconCls: 'button_menu_ext ICON_CASES_NOTES', + tooltip: { + title: _('ID_CASES_NOTES'), + text: _('ID_SHOW_CASES_NOTES') + }, + toggleHandler: function (btn, pressed) { + if (pressed) { + openCaseNotesWindow(); + } else { + closeCaseNotesWindow(); + } + } + }] + }; + + /** + * Get Parameters from URL + * @returns {*} + */ + function getParameterURL() { + var item, + key = false, + result = {}, + url = location.search.substring(1), + regExp = /([^&=]+)=([^&]*)/g; + if (arguments.length > 0 && arguments[0].length > 1) { + key = arguments[0]; + } + while (item = regExp.exec(url)) { + if (key !== false && decodeURIComponent(item[1]) === key) { + return decodeURIComponent(item[2]); + } + else if (key === false) { + result[decodeURIComponent(item[1])] = decodeURIComponent(item[2]); + } + } + return key === false ? result : null; + } + + var urlAction = getParameterURL('action'); + if (this.showCustomForm && this.showCustomForm === true && (urlAction === 'unassigned' || this.canClaimCase === true)) { + navPanel.items[navPanel.items.length] = navPanelBottom; + } var viewport = new Ext.Viewport({ layout: 'border', @@ -1358,6 +1471,7 @@ Ext.onReady(function(){ Actions.pauseCase = function() { + Ext.getCmp('submitPauseCase').setDisabled(true); Ext.Ajax.request({ url : 'ajaxListener' , params : {action : 'verifySession'}, @@ -1389,6 +1503,7 @@ Ext.onReady(function(){ var paramsNote = '&NOTE_REASON=' + noteReasonTxt + '&NOTIFY_PAUSE=' + notifyReasonVal; var unpauseDate = Ext.getCmp('unpauseDate').getValue(); if( unpauseDate == '') { + Ext.getCmp('submitPauseCase').setDisabled(false); return; } else { unpauseDate = unpauseDate.format('Y-m-d'); @@ -1419,6 +1534,7 @@ Ext.onReady(function(){ }, failure: function ( res, req) { PMExt.error(_('ID_ERROR'), req.result.msg); + Ext.getCmp('submitPauseCase').setDisabled(false); } }); } @@ -1427,6 +1543,7 @@ Ext.onReady(function(){ if (typeof(result.responseText) != 'undefined') { Ext.MessageBox.alert( _('ID_FAILED'), result.responseText); } + Ext.getCmp('submitPauseCase').setDisabled(false); } }); } @@ -1891,4 +2008,3 @@ Ext.onReady(function(){ node.select(); } - diff --git a/workflow/engine/templates/designer/index.html b/workflow/engine/templates/designer/index.html index d2da471e7..815b3023d 100644 --- a/workflow/engine/templates/designer/index.html +++ b/workflow/engine/templates/designer/index.html @@ -30,7 +30,11 @@ var SYS_LANG = "{$SYS_LANG}"; var SYS_SKIN = "{$SYS_SKIN}"; var HTTP_SERVER_HOSTNAME = "{$HTTP_SERVER_HOSTNAME}"; +<<<<<<< HEAD var PMDYNAFORM_FIRST_TIME = "{$PMDYNAFORM_FIRST_TIME}" === "1"; +======= + var maxFileSizeInformation = {$maxFileSizeInformation}; +>>>>>>> origin/develop @@ -89,6 +93,7 @@ var SYS_SKIN = "{$SYS_SKIN}"; var HTTP_SERVER_HOSTNAME = "{$HTTP_SERVER_HOSTNAME}"; var PMDYNAFORM_FIRST_TIME = "{$PMDYNAFORM_FIRST_TIME}" === "1"; + var maxFileSizeInformation = {$maxFileSizeInformation}; {foreach from=$sourceJs item=pathFile} diff --git a/workflow/engine/templates/mails/emailList.js b/workflow/engine/templates/mails/emailList.js index 2b91ac7db..0a9650bf6 100644 --- a/workflow/engine/templates/mails/emailList.js +++ b/workflow/engine/templates/mails/emailList.js @@ -33,19 +33,39 @@ Ext.onReady(function(){ ' {APP_PRO_TITLE}', '' ); - var columnRenderer = function(data, metadata, record, rowIndex,columnIndex, store) { - var new_text = metadata.style.split(';'); - var style = ''; - for (var i = 0; i < new_text.length -1 ; i++) { - var chain = new_text[i] +";"; - if (chain.indexOf('width') == -1) { - style = style + chain; - } - } - metadata.attr = 'ext:qtip="' + data + '" style="'+ style +' white-space: normal; "'; - return data; - }; + if(metadata.id == PMExt.emailConst.taskColumn.name){ + if((PMExt.emailConst.appMsgTypeWithoutTask.includes(record.data.APP_MSG_TYPE)) || (PMExt.emailConst.appMsgTypeWithConditionalTask.includes(record.data.APP_MSG_TYPE) && record.data.DEL_INDEX == 0)){ + data = PMExt.emailConst.taskColumn.defaultValue; + } + } + if(metadata.id == PMExt.emailConst.caseColumn.name){ + if(PMExt.emailConst.appMsgTypeWithoutCase.includes(record.data.APP_MSG_TYPE)){ + data = PMExt.emailConst.caseColumn.defaultValue; + } + } + if(metadata.id == PMExt.emailConst.processColumn.name){ + if(PMExt.emailConst.appMsgTypeWithoutProcess.includes(record.data.APP_MSG_TYPE)){ + data = PMExt.emailConst.processColumn.defaultValue; + } + } + if(metadata.id == PMExt.emailConst.numberColumn.name){ + if(PMExt.emailConst.appMsgTypeWithoutNumber.includes(record.data.APP_MSG_TYPE)){ + data = PMExt.emailConst.numberColumn.defaultValue; + } + } + var new_text = metadata.style.split(';'); + var style = ''; + for (var i = 0; i < new_text.length -1 ; i++) { + var chain = new_text[i] +";"; + if (chain.indexOf('width') == -1) { + style = style + chain; + } + } + metadata.attr = 'ext:qtip="' + data + '" style="'+ style +' white-space: normal; "'; + + return PMExt.escapeHtml(data); + }; var dateFrom = new Ext.form.DateField({ id:'dateFrom', diff --git a/workflow/engine/xmlform/cases/cases_Resume_Current_Task.xml b/workflow/engine/xmlform/cases/cases_Resume_Current_Task.xml index f251935e7..4e80eea7a 100644 --- a/workflow/engine/xmlform/cases/cases_Resume_Current_Task.xml +++ b/workflow/engine/xmlform/cases/cases_Resume_Current_Task.xml @@ -1,5 +1,5 @@ - - + + diff --git a/workflow/engine/xmlform/cases/cases_Resume_Current_Task_Title.xml b/workflow/engine/xmlform/cases/cases_Resume_Current_Task_Title.xml index 778e802cb..d6628fb8c 100644 --- a/workflow/engine/xmlform/cases/cases_Resume_Current_Task_Title.xml +++ b/workflow/engine/xmlform/cases/cases_Resume_Current_Task_Title.xml @@ -1,6 +1,6 @@ - - - + + + diff --git a/workflow/engine/xmlform/login/changePasswordpm3.html b/workflow/engine/xmlform/login/changePasswordpm3.html index ecbc54b0a..ae71c164c 100644 --- a/workflow/engine/xmlform/login/changePasswordpm3.html +++ b/workflow/engine/xmlform/login/changePasswordpm3.html @@ -14,6 +14,7 @@ {$form.USR_PASSWORD} {$form.USR_PASSWORD_CONFIRM} + {$form.__USR_PASSWORD_CHANGE__}