diff --git a/composer.json b/composer.json index 24016281..5909cce5 100644 --- a/composer.json +++ b/composer.json @@ -92,6 +92,7 @@ "npm-asset/sprintf-js": "~1.0.0", "npm-asset/codemirror": "~5.23.0", + "npm-asset/notifyjs": "~3.0.0", "bower-asset/admin-lte": "~2.3.0", "bower-asset/font-awesome": "~4.7.0", "bower-asset/ionicons": "~2.0.0", diff --git a/composer.lock b/composer.lock index 11d3e97c..5475238b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "8c2289ac491f1f1019f88be4f375b8a9", + "hash": "c36664adbc6a11c510a1a2ca21370a2a", + "content-hash": "dff41335ce906ddb872e66114ace5e50", "packages": [ { "name": "behat/gherkin", @@ -63,7 +64,7 @@ "gherkin", "parser" ], - "time": "2016-10-30T11:50:56+00:00" + "time": "2016-10-30 11:50:56" }, { "name": "block8/php-docblock-checker", @@ -116,7 +117,7 @@ "phpci", "testing" ], - "time": "2017-02-15T17:31:26+00:00" + "time": "2017-02-15 17:31:26" }, { "name": "bower-asset/admin-lte", @@ -310,7 +311,7 @@ "functional testing", "unit testing" ], - "time": "2018-02-26T23:29:41+00:00" + "time": "2018-02-26 23:29:41" }, { "name": "codeception/stub", @@ -343,20 +344,20 @@ "MIT" ], "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", - "time": "2018-02-18T13:56:56+00:00" + "time": "2018-02-18 13:56:56" }, { "name": "composer/ca-bundle", - "version": "1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "943b2c4fcad1ef178d16a713c2468bf7e579c288" + "reference": "d2c0a83b7533d6912e8d516756ebd34f893e9169" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/943b2c4fcad1ef178d16a713c2468bf7e579c288", - "reference": "943b2c4fcad1ef178d16a713c2468bf7e579c288", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/d2c0a83b7533d6912e8d516756ebd34f893e9169", + "reference": "d2c0a83b7533d6912e8d516756ebd34f893e9169", "shasum": "" }, "require": { @@ -365,7 +366,7 @@ "php": "^5.3.2 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5", "psr/log": "^1.0", "symfony/process": "^2.5 || ^3.0 || ^4.0" }, @@ -399,7 +400,7 @@ "ssl", "tls" ], - "time": "2017-11-29T09:37:33+00:00" + "time": "2018-03-29 19:57:20" }, { "name": "composer/installers", @@ -519,7 +520,7 @@ "zend", "zikula" ], - "time": "2017-12-29T09:13:20+00:00" + "time": "2017-12-29 09:13:20" }, { "name": "doctrine/instantiator", @@ -573,7 +574,7 @@ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "time": "2015-06-14 21:17:01" }, { "name": "facebook/webdriver", @@ -628,7 +629,7 @@ "selenium", "webdriver" ], - "time": "2017-11-15T11:08:09+00:00" + "time": "2017-11-15 11:08:09" }, { "name": "guzzlehttp/guzzle", @@ -690,7 +691,7 @@ "rest", "web service" ], - "time": "2017-02-28T22:50:30+00:00" + "time": "2017-02-28 22:50:30" }, { "name": "guzzlehttp/promises", @@ -741,7 +742,7 @@ "keywords": [ "promise" ], - "time": "2016-12-20T10:07:11+00:00" + "time": "2016-12-20 10:07:11" }, { "name": "guzzlehttp/psr7", @@ -806,7 +807,7 @@ "uri", "url" ], - "time": "2017-03-20T17:10:46+00:00" + "time": "2017-03-20 17:10:46" }, { "name": "jakub-onderka/php-parallel-lint", @@ -853,7 +854,7 @@ ], "description": "This tool check syntax of PHP files about 20x faster than serial check.", "homepage": "https://github.com/JakubOnderka/PHP-Parallel-Lint", - "time": "2015-12-15T10:42:16+00:00" + "time": "2015-12-15 10:42:16" }, { "name": "jasongrimes/paginator", @@ -898,7 +899,7 @@ "pagination", "paginator" ], - "time": "2015-10-15T09:42:44+00:00" + "time": "2015-10-15 09:42:44" }, { "name": "monolog/monolog", @@ -976,7 +977,7 @@ "logging", "psr-3" ], - "time": "2017-03-13T07:08:03+00:00" + "time": "2017-03-13 07:08:03" }, { "name": "myclabs/deep-copy", @@ -1021,7 +1022,7 @@ "object", "object graph" ], - "time": "2017-10-19T19:58:43+00:00" + "time": "2017-10-19 19:58:43" }, { "name": "nikic/php-parser", @@ -1072,7 +1073,7 @@ "parser", "php" ], - "time": "2018-02-28T20:30:58+00:00" + "time": "2018-02-28 20:30:58" }, { "name": "npm-asset/codemirror", @@ -1088,6 +1089,20 @@ "MIT" ] }, + { + "name": "npm-asset/notifyjs", + "version": "3.0.0", + "dist": { + "type": "tar", + "url": "https://registry.npmjs.org/notifyjs/-/notifyjs-3.0.0.tgz", + "reference": null, + "shasum": null + }, + "type": "npm-asset", + "license": [ + "MIT" + ] + }, { "name": "npm-asset/sprintf-js", "version": "1.0.3", @@ -1142,20 +1157,20 @@ ], "description": "Extend the composer/installers plugin to accept any arbitrary package type.", "homepage": "http://www.oomphinc.com/", - "time": "2017-03-31T16:57:39+00:00" + "time": "2017-03-31 16:57:39" }, { "name": "paragonie/random_compat", - "version": "v2.0.11", + "version": "v2.0.12", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8" + "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/5da4d3c796c275c55f057af5a643ae297d96b4d8", - "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/258c89a6b97de7dfaf5b8c7607d0478e236b04fb", + "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb", "shasum": "" }, "require": { @@ -1190,7 +1205,7 @@ "pseudorandom", "random" ], - "time": "2017-09-27T21:40:39+00:00" + "time": "2018-04-04 21:24:14" }, { "name": "pda/pheanstalk", @@ -1240,7 +1255,7 @@ "keywords": [ "beanstalkd" ], - "time": "2015-08-07T21:42:41+00:00" + "time": "2015-08-07 21:42:41" }, { "name": "pdepend/pdepend", @@ -1280,7 +1295,7 @@ "BSD-3-Clause" ], "description": "Official version of pdepend to be handled with Composer", - "time": "2017-12-13T13:21:38+00:00" + "time": "2017-12-13 13:21:38" }, { "name": "phpdocumentor/reflection-docblock", @@ -1329,7 +1344,7 @@ "email": "mike.vanriel@naenius.com" } ], - "time": "2016-01-25T08:17:30+00:00" + "time": "2016-01-25 08:17:30" }, { "name": "phploc/phploc", @@ -1378,7 +1393,7 @@ ], "description": "A tool for quickly measuring the size of a PHP project.", "homepage": "https://github.com/sebastianbergmann/phploc", - "time": "2017-11-18T17:35:43+00:00" + "time": "2017-11-18 17:35:43" }, { "name": "phpmd/phpmd", @@ -1444,7 +1459,7 @@ "phpmd", "pmd" ], - "time": "2017-01-20T14:41:10+00:00" + "time": "2017-01-20 14:41:10" }, { "name": "phpspec/prophecy", @@ -1507,7 +1522,7 @@ "spy", "stub" ], - "time": "2018-02-19T10:16:54+00:00" + "time": "2018-02-19 10:16:54" }, { "name": "phpunit/php-code-coverage", @@ -1570,7 +1585,7 @@ "testing", "xunit" ], - "time": "2017-04-02T07:44:40+00:00" + "time": "2017-04-02 07:44:40" }, { "name": "phpunit/php-file-iterator", @@ -1617,7 +1632,7 @@ "filesystem", "iterator" ], - "time": "2017-11-27T13:52:08+00:00" + "time": "2017-11-27 13:52:08" }, { "name": "phpunit/php-text-template", @@ -1658,7 +1673,7 @@ "keywords": [ "template" ], - "time": "2015-06-21T13:50:34+00:00" + "time": "2015-06-21 13:50:34" }, { "name": "phpunit/php-timer", @@ -1707,7 +1722,7 @@ "keywords": [ "timer" ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2017-02-26 11:10:40" }, { "name": "phpunit/php-token-stream", @@ -1756,7 +1771,7 @@ "keywords": [ "tokenizer" ], - "time": "2017-12-04T08:55:13+00:00" + "time": "2017-12-04 08:55:13" }, { "name": "phpunit/phpunit", @@ -1838,7 +1853,7 @@ "testing", "xunit" ], - "time": "2018-02-01T05:50:59+00:00" + "time": "2018-02-01 05:50:59" }, { "name": "phpunit/phpunit-mock-objects", @@ -1897,7 +1912,7 @@ "mock", "xunit" ], - "time": "2017-06-30T09:13:00+00:00" + "time": "2017-06-30 09:13:00" }, { "name": "pimple/pimple", @@ -1943,7 +1958,7 @@ "container", "dependency injection" ], - "time": "2015-09-11T15:10:35+00:00" + "time": "2015-09-11 15:10:35" }, { "name": "psr/cache", @@ -1989,7 +2004,7 @@ "psr", "psr-6" ], - "time": "2016-08-06T20:24:11+00:00" + "time": "2016-08-06 20:24:11" }, { "name": "psr/container", @@ -2038,7 +2053,7 @@ "container-interop", "psr" ], - "time": "2017-02-14T16:28:37+00:00" + "time": "2017-02-14 16:28:37" }, { "name": "psr/http-message", @@ -2088,7 +2103,7 @@ "request", "response" ], - "time": "2016-08-06T14:39:51+00:00" + "time": "2016-08-06 14:39:51" }, { "name": "psr/log", @@ -2135,7 +2150,7 @@ "psr", "psr-3" ], - "time": "2016-10-10T12:19:37+00:00" + "time": "2016-10-10 12:19:37" }, { "name": "psr/simple-cache", @@ -2183,7 +2198,7 @@ "psr-16", "simple-cache" ], - "time": "2017-10-23T01:57:42+00:00" + "time": "2017-10-23 01:57:42" }, { "name": "robmorgan/phinx", @@ -2249,7 +2264,7 @@ "migrations", "phinx" ], - "time": "2017-06-05T13:30:19+00:00" + "time": "2017-06-05 13:30:19" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -2294,7 +2309,7 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04T06:30:41+00:00" + "time": "2017-03-04 06:30:41" }, { "name": "sebastian/comparator", @@ -2358,7 +2373,7 @@ "compare", "equality" ], - "time": "2017-01-29T09:50:25+00:00" + "time": "2017-01-29 09:50:25" }, { "name": "sebastian/diff", @@ -2410,7 +2425,7 @@ "keywords": [ "diff" ], - "time": "2017-05-22T07:24:03+00:00" + "time": "2017-05-22 07:24:03" }, { "name": "sebastian/environment", @@ -2460,7 +2475,7 @@ "environment", "hhvm" ], - "time": "2016-11-26T07:53:53+00:00" + "time": "2016-11-26 07:53:53" }, { "name": "sebastian/exporter", @@ -2527,7 +2542,7 @@ "export", "exporter" ], - "time": "2016-11-19T08:54:04+00:00" + "time": "2016-11-19 08:54:04" }, { "name": "sebastian/finder-facade", @@ -2566,7 +2581,7 @@ ], "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", "homepage": "https://github.com/sebastianbergmann/finder-facade", - "time": "2017-11-18T17:31:49+00:00" + "time": "2017-11-18 17:31:49" }, { "name": "sebastian/global-state", @@ -2617,7 +2632,7 @@ "keywords": [ "global state" ], - "time": "2015-10-12T03:26:01+00:00" + "time": "2015-10-12 03:26:01" }, { "name": "sebastian/object-enumerator", @@ -2663,7 +2678,7 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-02-18T15:18:39+00:00" + "time": "2017-02-18 15:18:39" }, { "name": "sebastian/phpcpd", @@ -2714,7 +2729,7 @@ ], "description": "Copy/Paste Detector (CPD) for PHP code.", "homepage": "https://github.com/sebastianbergmann/phpcpd", - "time": "2016-04-17T19:32:49+00:00" + "time": "2016-04-17 19:32:49" }, { "name": "sebastian/recursion-context", @@ -2767,7 +2782,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2016-11-19T07:33:16+00:00" + "time": "2016-11-19 07:33:16" }, { "name": "sebastian/resource-operations", @@ -2809,7 +2824,7 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" + "time": "2015-07-28 20:34:47" }, { "name": "sebastian/version", @@ -2852,7 +2867,7 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" + "time": "2016-10-03 07:35:21" }, { "name": "sensiolabs/ansi-to-html", @@ -2896,7 +2911,7 @@ } ], "description": "A library to convert a text with ANSI codes to HTML", - "time": "2017-05-02T00:53:29+00:00" + "time": "2017-05-02 00:53:29" }, { "name": "sensiolabs/security-checker", @@ -2941,7 +2956,7 @@ } ], "description": "A security checker for your composer.lock", - "time": "2017-07-24T11:42:56+00:00" + "time": "2017-07-24 11:42:56" }, { "name": "squizlabs/php_codesniffer", @@ -3019,7 +3034,7 @@ "phpcs", "standards" ], - "time": "2017-03-01T22:17:45+00:00" + "time": "2017-03-01 22:17:45" }, { "name": "swiftmailer/swiftmailer", @@ -3073,20 +3088,20 @@ "mail", "mailer" ], - "time": "2018-01-23T07:37:21+00:00" + "time": "2018-01-23 07:37:21" }, { "name": "symfony/browser-kit", - "version": "v3.4.6", + "version": "v3.4.7", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "490f27762705c8489bd042fe3e9377a191dba9b4" + "reference": "840bb6f0d5b3701fd768b68adf7193c2d0f98f79" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/490f27762705c8489bd042fe3e9377a191dba9b4", - "reference": "490f27762705c8489bd042fe3e9377a191dba9b4", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/840bb6f0d5b3701fd768b68adf7193c2d0f98f79", + "reference": "840bb6f0d5b3701fd768b68adf7193c2d0f98f79", "shasum": "" }, "require": { @@ -3130,20 +3145,20 @@ ], "description": "Symfony BrowserKit Component", "homepage": "https://symfony.com", - "time": "2018-01-03T07:37:34+00:00" + "time": "2018-03-19 22:32:39" }, { "name": "symfony/cache", - "version": "v3.4.6", + "version": "v3.4.7", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "cce49c7aa2fc82077355c8a6dfcd9e619abe6e98" + "reference": "13255ddd056e49f3154747943f8ee175d555d394" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/cce49c7aa2fc82077355c8a6dfcd9e619abe6e98", - "reference": "cce49c7aa2fc82077355c8a6dfcd9e619abe6e98", + "url": "https://api.github.com/repos/symfony/cache/zipball/13255ddd056e49f3154747943f8ee175d555d394", + "reference": "13255ddd056e49f3154747943f8ee175d555d394", "shasum": "" }, "require": { @@ -3200,20 +3215,20 @@ "caching", "psr6" ], - "time": "2018-02-11T14:42:07+00:00" + "time": "2018-04-02 14:35:16" }, { "name": "symfony/config", - "version": "v3.4.6", + "version": "v3.4.7", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "05e10567b529476a006b00746c5f538f1636810e" + "reference": "7c2a9d44f4433863e9bca682e7f03609234657f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/05e10567b529476a006b00746c5f538f1636810e", - "reference": "05e10567b529476a006b00746c5f538f1636810e", + "url": "https://api.github.com/repos/symfony/config/zipball/7c2a9d44f4433863e9bca682e7f03609234657f9", + "reference": "7c2a9d44f4433863e9bca682e7f03609234657f9", "shasum": "" }, "require": { @@ -3263,20 +3278,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2018-02-14T10:03:57+00:00" + "time": "2018-03-19 22:32:39" }, { "name": "symfony/console", - "version": "v3.4.6", + "version": "v3.4.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "067339e9b8ec30d5f19f5950208893ff026b94f7" + "reference": "d4bb70fa24d540c309d88a9d6e43fb2d339b1fbf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/067339e9b8ec30d5f19f5950208893ff026b94f7", - "reference": "067339e9b8ec30d5f19f5950208893ff026b94f7", + "url": "https://api.github.com/repos/symfony/console/zipball/d4bb70fa24d540c309d88a9d6e43fb2d339b1fbf", + "reference": "d4bb70fa24d540c309d88a9d6e43fb2d339b1fbf", "shasum": "" }, "require": { @@ -3332,20 +3347,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-02-26T15:46:28+00:00" + "time": "2018-04-03 05:22:50" }, { "name": "symfony/css-selector", - "version": "v3.4.6", + "version": "v3.4.7", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "544655f1fc078a9cd839fdda2b7b1e64627c826a" + "reference": "519a80d7c1d95c6cc0b67f686d15fe27c6910de0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/544655f1fc078a9cd839fdda2b7b1e64627c826a", - "reference": "544655f1fc078a9cd839fdda2b7b1e64627c826a", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/519a80d7c1d95c6cc0b67f686d15fe27c6910de0", + "reference": "519a80d7c1d95c6cc0b67f686d15fe27c6910de0", "shasum": "" }, "require": { @@ -3385,20 +3400,20 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2018-02-03T14:55:07+00:00" + "time": "2018-03-19 22:32:39" }, { "name": "symfony/debug", - "version": "v3.4.6", + "version": "v3.4.7", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "9b1071f86e79e1999b3d3675d2e0e7684268b9bc" + "reference": "9cf7c2271cfb89ef9727db1b740ca77be57bf9d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/9b1071f86e79e1999b3d3675d2e0e7684268b9bc", - "reference": "9b1071f86e79e1999b3d3675d2e0e7684268b9bc", + "url": "https://api.github.com/repos/symfony/debug/zipball/9cf7c2271cfb89ef9727db1b740ca77be57bf9d7", + "reference": "9cf7c2271cfb89ef9727db1b740ca77be57bf9d7", "shasum": "" }, "require": { @@ -3441,20 +3456,20 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2018-02-28T21:49:22+00:00" + "time": "2018-04-03 05:22:50" }, { "name": "symfony/dependency-injection", - "version": "v3.4.6", + "version": "v3.4.7", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "12e901abc1cb0d637a0e5abe9923471361d96b07" + "reference": "24a68710c6ddc1e3d159a110cef94cedfcf3c611" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/12e901abc1cb0d637a0e5abe9923471361d96b07", - "reference": "12e901abc1cb0d637a0e5abe9923471361d96b07", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/24a68710c6ddc1e3d159a110cef94cedfcf3c611", + "reference": "24a68710c6ddc1e3d159a110cef94cedfcf3c611", "shasum": "" }, "require": { @@ -3512,20 +3527,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2018-03-04T03:54:53+00:00" + "time": "2018-03-29 11:25:31" }, { "name": "symfony/dom-crawler", - "version": "v3.4.6", + "version": "v3.4.7", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "2bb5d3101cc01f4fe580e536daf4f1959bc2d24d" + "reference": "1a4cffeb059226ff6bee9f48acb388faf674afff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/2bb5d3101cc01f4fe580e536daf4f1959bc2d24d", - "reference": "2bb5d3101cc01f4fe580e536daf4f1959bc2d24d", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/1a4cffeb059226ff6bee9f48acb388faf674afff", + "reference": "1a4cffeb059226ff6bee9f48acb388faf674afff", "shasum": "" }, "require": { @@ -3568,11 +3583,11 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2018-02-22T10:48:49+00:00" + "time": "2018-03-19 22:32:39" }, { "name": "symfony/event-dispatcher", - "version": "v3.4.6", + "version": "v3.4.7", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -3631,11 +3646,11 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2018-02-14T10:03:57+00:00" + "time": "2018-02-14 10:03:57" }, { "name": "symfony/filesystem", - "version": "v3.4.6", + "version": "v3.4.7", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", @@ -3680,20 +3695,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2018-02-22T10:48:49+00:00" + "time": "2018-02-22 10:48:49" }, { "name": "symfony/finder", - "version": "v3.4.6", + "version": "v3.4.7", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "a479817ce0a9e4adfd7d39c6407c95d97c254625" + "reference": "7a2e1299cc0c4162996f18e347b6356729a55317" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/a479817ce0a9e4adfd7d39c6407c95d97c254625", - "reference": "a479817ce0a9e4adfd7d39c6407c95d97c254625", + "url": "https://api.github.com/repos/symfony/finder/zipball/7a2e1299cc0c4162996f18e347b6356729a55317", + "reference": "7a2e1299cc0c4162996f18e347b6356729a55317", "shasum": "" }, "require": { @@ -3729,7 +3744,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-03-05T18:28:11+00:00" + "time": "2018-03-28 18:23:39" }, { "name": "symfony/polyfill-apcu", @@ -3785,7 +3800,7 @@ "portable", "shim" ], - "time": "2018-01-30T19:27:44+00:00" + "time": "2018-01-30 19:27:44" }, { "name": "symfony/polyfill-mbstring", @@ -3844,20 +3859,20 @@ "portable", "shim" ], - "time": "2018-01-30T19:27:44+00:00" + "time": "2018-01-30 19:27:44" }, { "name": "symfony/process", - "version": "v3.4.6", + "version": "v3.4.7", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "cc4aea21f619116aaf1c58016a944e4821c8e8af" + "reference": "4b7d64e852886319e93ddfdecff0d744ab87658b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/cc4aea21f619116aaf1c58016a944e4821c8e8af", - "reference": "cc4aea21f619116aaf1c58016a944e4821c8e8af", + "url": "https://api.github.com/repos/symfony/process/zipball/4b7d64e852886319e93ddfdecff0d744ab87658b", + "reference": "4b7d64e852886319e93ddfdecff0d744ab87658b", "shasum": "" }, "require": { @@ -3893,20 +3908,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-02-12T17:55:00+00:00" + "time": "2018-04-03 05:22:50" }, { "name": "symfony/yaml", - "version": "v3.4.6", + "version": "v3.4.7", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "6af42631dcf89e9c616242c900d6c52bd53bd1bb" + "reference": "a42f9da85c7c38d59f5e53f076fe81a091f894d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/6af42631dcf89e9c616242c900d6c52bd53bd1bb", - "reference": "6af42631dcf89e9c616242c900d6c52bd53bd1bb", + "url": "https://api.github.com/repos/symfony/yaml/zipball/a42f9da85c7c38d59f5e53f076fe81a091f894d0", + "reference": "a42f9da85c7c38d59f5e53f076fe81a091f894d0", "shasum": "" }, "require": { @@ -3951,7 +3966,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2018-02-16T09:50:28+00:00" + "time": "2018-04-03 05:14:20" }, { "name": "theseer/fdomdocument", @@ -3991,7 +4006,7 @@ ], "description": "The classes contained within this repository extend the standard DOM to use exceptions at all occasions of errors instead of PHP warnings or notices. They also add various custom methods and shortcuts for convenience and to simplify the usage of DOM.", "homepage": "https://github.com/theseer/fDOMDocument", - "time": "2017-06-30T11:53:12+00:00" + "time": "2017-06-30 11:53:12" } ], "packages-dev": [ @@ -4048,20 +4063,20 @@ "testing", "xunit" ], - "time": "2016-12-02T14:39:14+00:00" + "time": "2016-12-02 14:39:14" }, { "name": "symfony/var-dumper", - "version": "v3.4.6", + "version": "v3.4.7", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "80964679d81da3d5618519e0e4be488c3d7ecd7d" + "reference": "6f502127b1bb85f7f30f8bc1fb60570a10431863" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/80964679d81da3d5618519e0e4be488c3d7ecd7d", - "reference": "80964679d81da3d5618519e0e4be488c3d7ecd7d", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6f502127b1bb85f7f30f8bc1fb60570a10431863", + "reference": "6f502127b1bb85f7f30f8bc1fb60570a10431863", "shasum": "" }, "require": { @@ -4117,7 +4132,7 @@ "debug", "dump" ], - "time": "2018-02-22T17:29:24+00:00" + "time": "2018-04-03 05:22:50" } ], "aliases": [], diff --git a/public/assets/js/app.js b/public/assets/js/app.js index dcf7c630..03fe6799 100644 --- a/public/assets/js/app.js +++ b/public/assets/js/app.js @@ -1,6 +1,18 @@ var PHPCensor = { intervals: {}, widgets: {}, + webNotifiedBuilds: [], + /* + @var STATUS Refer to \PHPCensor\Model\Build.php constants. + TODO: Transfer this variable to Build JS class so + Build JS itself can use it as well. + */ + STATUS: [ + 'Pending', + 'Running', + 'Success', + 'Failed' + ], init: function () { $(document).ready(function () { @@ -19,6 +31,128 @@ var PHPCensor = { }); }, + /** + * Shallow comparison that determines that the build + * has been shown as at least once as a web notification. + * Also adds the build to a list of shown web notifications + * if it's not found in the list. + * @param object build + * @return boolean + */ + isWebNotifiedBuild: function (build) { + var o = PHPCensor.webNotifiedBuilds; + for (var i = 0; i < o.length; i++) { + var webNotifiedBuild = o[i]; + var b = + webNotifiedBuild.projectTitle === build.projectTitle && + webNotifiedBuild.branch === build.branch && + webNotifiedBuild.status === build.status && + webNotifiedBuild.datePerformed === build.datePerformed && + webNotifiedBuild.dateFinished === build.dateFinished; + if (b) { + return true; + } + } + /* + It's impossible to remember or use all previously shown + builds. So let's clear them out once they reach 1000. + @var 1000 Estimated. + */ + if (PHPCensor.webNotifiedBuilds.length > 1000) { + PHPCensor.webNotifiedBuilds = []; + } + PHPCensor.webNotifiedBuilds.push(build); + return false; + }, + + /** + * Web notification. + * Chrome doesn't allow insecure protocols. + * Enable HTTPS even on localhost in order for + * web notifications to work properly. + * @param object data Contains an array of builds. + * @return void + */ + showWebNotification: function (data) { + var pending = data.pending; + var running = data.running; + var success = data.success; + var failed = data.failed; + var notification = null; + + //Determine which notification to show. + //TODO: Refactor. Use foreach. + if (pending && pending.count > 0) { + notification = pending; + } + else if (running && running.count > 0) { + notification = running; + } + else if (success && success.count > 0) { + notification = success; + } + else if (failed && failed.count > 0) { + notification = failed; + } + + if (notification) { + var msg = ''; + if (!Notify.needsPermission) { + var items = notification.items; + for (var item in items) { + var build = items[item].build; + var projTitle = build.project_title; + var branch = build.branch; + var status = PHPCensor.STATUS[build.status]; + var datePerformed = build.date_performed; + var dateFinished = build.date_finished; + var rn = "\r\n"; + + var build = { + projectTitle: projTitle, + branch: branch, + status: status, + datePerformed: datePerformed, + dateFinished: dateFinished + }; + + //Ignore if the last displayed notification is + //similar to what we're again about to display. + if (!PHPCensor.isWebNotifiedBuild(build)) { + msg += + 'Project title: ' + projTitle + rn + + 'Git branch: ' + branch + rn + + 'Status: ' + status + rn; + + //Build details is empty during + //widget-all-projects-update. + if (datePerformed.length > 0) { + msg += datePerformed + rn; + } + + if (dateFinished.length > 0) { + msg += dateFinished; + } + + new Notify( + 'PHP Censor Web Notification', + {body: msg} + ).show(); + } + + } + + } + else if (Notify.isSupported()) { + Notify.requestPermission(null, function(){ + msg = 'Web notifications permission ' + + 'has been denied by the user.' + console.warn(msg); + }); + } + } + }, + getBuilds: function () { $.ajax({ url: APP_URL + 'build/ajax-queue', @@ -29,6 +163,14 @@ var PHPCensor = { error: PHPCensor.handleFailedAjax }); + + $.ajax({ + url: APP_URL + 'web-notifications/builds-updated', + success: function (data) { + PHPCensor.showWebNotification(data); + }, + error: PHPCensor.handleFailedAjax + }); }, getProjectBuilds: function () { diff --git a/public/assets/js/dashboard-widgets/all_projects.js b/public/assets/js/dashboard-widgets/all_projects.js index a13bcf58..1f767a57 100644 --- a/public/assets/js/dashboard-widgets/all_projects.js +++ b/public/assets/js/dashboard-widgets/all_projects.js @@ -33,6 +33,16 @@ PHPCensor.widgets.allProjects = { error: PHPCensor.handleFailedAjax }); + + $.ajax({ + url: APP_URL + + 'web-notifications/widgets-all-projects-update/' + + projectId, + success: function (data) { + PHPCensor.showWebNotification(data); + }, + error: PHPCensor.handleFailedAjax + }); }); } }; diff --git a/src/Controller/WebNotificationsController.php b/src/Controller/WebNotificationsController.php new file mode 100644 index 00000000..ec0787b0 --- /dev/null +++ b/src/Controller/WebNotificationsController.php @@ -0,0 +1,94 @@ +buildStore = Factory::getStore('Build'); + } + + /** + * Provides JSON format for web notification UI of all last builds that have success and failed status. + * This is similar to WidgetAllProjectsController::update() but instead, this only returns JSON. + * + * @param int $projectId + * + * @return \PHPCensor\Http\Response\JsonResponse + * + * @see \PHPCensor\Controller\WidgetAllProjectsController + */ + public function widgetsAllProjectsUpdate($projectId) + { + $success = $this->buildStore->getLastBuildByStatus($projectId, Build::STATUS_SUCCESS); + $failed = $this->buildStore->getLastBuildByStatus($projectId, Build::STATUS_FAILED); + + $oSuccess = WebNotificationService::formatBuild($success); + $oFailed = WebNotificationService::formatBuild($failed); + + $aSuccess = [ + 'count' => count($oSuccess), + 'items' => [$projectId => ['build' => $oSuccess]] + ]; + $aFailed = [ + 'count' => count($oFailed), + 'items' => [$projectId => ['build' => $oFailed]] + ]; + + $builds = [ + 'success' => $aSuccess, + 'failed' => $aFailed + ]; + + $response = new JsonResponse(); + $response->setContent($builds); + + return $response; + } + + + /** + * Provides JSON format for web notification UI of all last builds that have pending and running status. + * This is similar to WidgetAllProjectsController::update() but instead, this only returns JSON. + * + * @return JsonResponse + * + * @throws \PHPCensor\Exception\HttpException + */ + public function buildsUpdated() + { + $pending = $this->buildStore->getByStatus(Build::STATUS_PENDING); + $running = $this->buildStore->getByStatus(Build::STATUS_RUNNING); + + $result = [ + 'pending' => WebNotificationService::formatBuilds($pending), + 'running' => WebNotificationService::formatBuilds($running) + ]; + + $response = new JsonResponse(); + $response->setContent($result); + + return $response; + } +} diff --git a/src/Controller/WidgetAllProjectsController.php b/src/Controller/WidgetAllProjectsController.php index 48822749..8846dcfa 100644 --- a/src/Controller/WidgetAllProjectsController.php +++ b/src/Controller/WidgetAllProjectsController.php @@ -104,6 +104,8 @@ class WidgetAllProjectsController extends WebController * Get a summary of the project groups we have, and what projects they have in them. * * @return array + * + * @throws \Exception */ protected function getGroupInfo() { @@ -127,6 +129,8 @@ class WidgetAllProjectsController extends WebController * @param integer $projectId * * @return Response + * + * @throws \PHPCensor\Exception\HttpException */ public function update($projectId) { diff --git a/src/Controller/WidgetBuildErrorsController.php b/src/Controller/WidgetBuildErrorsController.php index 706bf601..589262b6 100644 --- a/src/Controller/WidgetBuildErrorsController.php +++ b/src/Controller/WidgetBuildErrorsController.php @@ -52,6 +52,8 @@ class WidgetBuildErrorsController extends WebController /** * @return Response + * + * @throws \PHPCensor\Exception\HttpException */ public function update() { @@ -65,6 +67,8 @@ class WidgetBuildErrorsController extends WebController * @param View $view * * @return string + * + * @throws \PHPCensor\Exception\HttpException */ protected function renderAllProjectsLatestBuilds($view) { diff --git a/src/Service/WebNotificationService.php b/src/Service/WebNotificationService.php new file mode 100644 index 00000000..8acea99c --- /dev/null +++ b/src/Service/WebNotificationService.php @@ -0,0 +1,73 @@ + $builds['count'], 'items' => []]; + + foreach ($builds['items'] as $buildItem) { + $build = self::formatBuild($buildItem); + $rtn['items'][$buildItem->getId()]['build'] = $build; + } + + ksort($rtn['items']); + return $rtn; + } + + /** + * Provides structured keys for web notification. + * + * @param Build $build + * + * @return array + */ + public static function formatBuild($build) + { + if (empty($build) || is_null($build)) { + return []; + } + + $status = $build->getStatus(); + $datePerformed = ''; + $dateFinished = ''; + + if ($status === Build::STATUS_PENDING) { + $datePerformed = 'Created: ' . $build->getCreateDate()->format('H:i'); + } elseif ($status === Build::STATUS_RUNNING) { + $datePerformed = 'Started: ' . $build->getStartDate()->format('H:i'); + } + + if (!is_null($build->getFinishDate())) { + $dateFinished = 'Finished: ' . $build->getFinishDate()->format('H:i'); + } + + return [ + 'branch' => $build->getBranch(), + 'url' => APP_URL . 'build/view/' . $build->getId(), + 'committer_email' => $build->getCommitterEmail(), + 'img_src' => 'https://www.gravatar.com/avatar/' . md5($build->getCommitterEmail()) . '?d=mm&s=40', + 'project_title' => $build->getProject()->getTitle(), + 'status' => $status, + 'date_performed' => $datePerformed, + 'date_finished' => $dateFinished + ]; + } +} diff --git a/src/View/layout.phtml b/src/View/layout.phtml index e4892348..ca646926 100644 --- a/src/View/layout.phtml +++ b/src/View/layout.phtml @@ -32,6 +32,7 @@ $user = $this->getUser(); +