From 2ab092dbb2192f066491735bd3913abf64609504 Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 12 Apr 2022 20:08:20 +0100 Subject: [PATCH 01/18] * Re-run build --- .github/workflows/main.yml | 2 +- composer.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a3478e2..1572385 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,5 +43,5 @@ jobs: - name: Install WP Tests run: bash testing/bin/install-wp-tests.sh wordpress_test username password 127.0.0.1 latest true - - name: phpunit tests + - name: Run PHPUnit tests run: ./vendor/bin/phpunit diff --git a/composer.json b/composer.json index 7117d4c..2db5337 100644 --- a/composer.json +++ b/composer.json @@ -6,8 +6,8 @@ "WpMailCatcher\\": "src/" } }, - "require": {}, "require-dev": { - "phpunit/phpunit": "5.7.*" + "phpunit/phpunit": "6.5.*", + "yoast/phpunit-polyfills": "^1.0" } } From 995e66feddb4c9fb3f6ec7be3fad39d3155362e6 Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 12 Apr 2022 20:15:56 +0100 Subject: [PATCH 02/18] * Drop support for PHP 5.6 --- .github/workflows/main.yml | 2 +- composer.lock | 1792 ++++++++++++++++++++++++++++++++++++ readme.txt | 4 +- 3 files changed, 1795 insertions(+), 3 deletions(-) create mode 100644 composer.lock diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1572385..684adfc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ jobs: strategy: matrix: operating-system: [ubuntu-latest] - php-versions: ['7.3', '7.2', '7.0', '5.6'] + php-versions: ['8.0', '7.3', '7.2', '7.0'] name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} steps: - name: Checkout diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..3cc1247 --- /dev/null +++ b/composer.lock @@ -0,0 +1,1792 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "bb36dd706229c61c28834f9eec9985ad", + "packages": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc", + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.22" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.4.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-03-03T08:28:38+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2022-03-03T13:19:32+00:00" + }, + { + "name": "phar-io/manifest", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^1.0.1", + "php": "^5.6 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/master" + }, + "time": "2017-03-05T18:14:27+00:00" + }, + { + "name": "phar-io/version", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/master" + }, + "time": "2017-03-05T17:38:23+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + }, + "time": "2021-10-19T17:43:47+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "77a32518733312af16a44300404e945338981de3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3", + "reference": "77a32518733312af16a44300404e945338981de3", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1" + }, + "time": "2022-03-15T21:29:03+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.10.3", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "451c3cd1418cf640de218914901e51b064abb093" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093", + "reference": "451c3cd1418cf640de218914901e51b064abb093", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", + "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5 || ^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/v1.10.3" + }, + "time": "2020-03-05T15:02:03+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "5.3.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "c89677919c5dd6d3b3852f230a663118762218ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac", + "reference": "c89677919c5dd6d3b3852f230a663118762218ac", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.0", + "phpunit/php-file-iterator": "^1.4.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^2.0.1", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^3.0", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-xdebug": "^2.5.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/5.3" + }, + "time": "2018-04-06T15:36:58+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "irc": "irc://irc.freenode.net/phpunit", + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/1.4.5" + }, + "time": "2017-11-27T13:52:08+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" + }, + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/master" + }, + "time": "2017-02-26T11:10:40+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "791198a2c6254db10131eecfe8c06670700904db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", + "reference": "791198a2c6254db10131eecfe8c06670700904db", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.2.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", + "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master" + }, + "abandoned": true, + "time": "2017-11-27T05:48:46+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "6.5.14", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bac23fe7ff13dbdb461481f706f0e9fe746334b7", + "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "^1.6.1", + "phar-io/manifest": "^1.0.1", + "phar-io/version": "^1.0", + "php": "^7.0", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^5.3", + "phpunit/php-file-iterator": "^1.4.3", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^1.0.9", + "phpunit/phpunit-mock-objects": "^5.0.9", + "sebastian/comparator": "^2.1", + "sebastian/diff": "^2.0", + "sebastian/environment": "^3.1", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^2.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^1.0", + "sebastian/version": "^2.0.1" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2", + "phpunit/dbunit": "<3.0" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-xdebug": "*", + "phpunit/php-invoker": "^1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.5.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/6.5.14" + }, + "time": "2019-02-01T05:22:47+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "5.0.10", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/cd1cf05c553ecfec36b170070573e540b67d3f1f", + "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.5", + "php": "^7.0", + "phpunit/php-text-template": "^1.2.1", + "sebastian/exporter": "^3.1" + }, + "conflict": { + "phpunit/phpunit": "<6.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.5.11" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit-mock-objects/issues", + "source": "https://github.com/sebastianbergmann/phpunit-mock-objects/tree/5.0.10" + }, + "abandoned": true, + "time": "2018-08-09T05:50:03+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T08:15:22+00:00" + }, + { + "name": "sebastian/comparator", + "version": "2.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", + "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/diff": "^2.0 || ^3.0", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/master" + }, + "time": "2018-02-01T13:46:46+00:00" + }, + { + "name": "sebastian/diff", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/master" + }, + "time": "2017-08-03T08:09:46+00:00" + }, + { + "name": "sebastian/environment", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/master" + }, + "time": "2017-07-01T08:51:00+00:00" + }, + { + "name": "sebastian/exporter", + "version": "3.1.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "0c32ea2e40dbf59de29f3b49bf375176ce7dd8db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/0c32ea2e40dbf59de29f3b49bf375176ce7dd8db", + "reference": "0c32ea2e40dbf59de29f3b49bf375176ce7dd8db", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/3.1.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-11-11T13:51:24+00:00" + }, + { + "name": "sebastian/global-state", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/2.0.0" + }, + "time": "2017-04-27T15:39:26+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "3.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", + "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:40:27+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", + "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:37:18+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb", + "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:34:24+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/master" + }, + "time": "2015-07-28T20:34:47+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/master" + }, + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "30885182c981ab175d4d034db0f6f469898070ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-10-20T20:35:02+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.10.0" + }, + "time": "2021-03-09T10:59:23+00:00" + }, + { + "name": "yoast/phpunit-polyfills", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/Yoast/PHPUnit-Polyfills.git", + "reference": "5ea3536428944955f969bc764bbe09738e151ada" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/5ea3536428944955f969bc764bbe09738e151ada", + "reference": "5ea3536428944955f969bc764bbe09738e151ada", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + }, + "require-dev": { + "yoast/yoastcs": "^2.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev", + "dev-develop": "1.x-dev" + } + }, + "autoload": { + "files": [ + "phpunitpolyfills-autoload.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Team Yoast", + "email": "support@yoast.com", + "homepage": "https://yoast.com" + }, + { + "name": "Contributors", + "homepage": "https://github.com/Yoast/PHPUnit-Polyfills/graphs/contributors" + } + ], + "description": "Set of polyfills for changed PHPUnit functionality to allow for creating PHPUnit cross-version compatible tests", + "homepage": "https://github.com/Yoast/PHPUnit-Polyfills", + "keywords": [ + "phpunit", + "polyfill", + "testing" + ], + "support": { + "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues", + "source": "https://github.com/Yoast/PHPUnit-Polyfills" + }, + "time": "2021-11-23T01:37:03+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/readme.txt b/readme.txt index aa28b2f..c6f7719 100644 --- a/readme.txt +++ b/readme.txt @@ -2,8 +2,8 @@ Contributors: Wardee Tags: mail logging, email log, email logger, logging, email logging, mail, crm Requires at least: 4.7 -Tested up to: 5.8 -Requires PHP: 5.6 +Tested up to: 5.9 +Requires PHP: 7.2 Stable tag: 1.5.4 License: GNU General Public License v3.0 License URI: https://raw.githubusercontent.com/JWardee/wp-mail-catcher/master/LICENSE From 53c58c761e9dcd6e90496a82e263c5f99f422ef6 Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 12 Apr 2022 20:17:24 +0100 Subject: [PATCH 03/18] * Build fix --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 684adfc..26dbb2a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ jobs: strategy: matrix: operating-system: [ubuntu-latest] - php-versions: ['8.0', '7.3', '7.2', '7.0'] + php-versions: ['7.3', '7.2', '7.0'] name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} steps: - name: Checkout From 83f5f636da2ba7051b6bd4711be8fce50667a96e Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 12 Apr 2022 20:19:34 +0100 Subject: [PATCH 04/18] * FIx build? --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 26dbb2a..9a8beb6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ jobs: strategy: matrix: operating-system: [ubuntu-latest] - php-versions: ['7.3', '7.2', '7.0'] + php-versions: ['7.3', '7.2'] name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} steps: - name: Checkout From afa48cc35c12436965fdf623bec3d81071646b33 Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 12 Apr 2022 20:53:09 +0100 Subject: [PATCH 05/18] * Updated readme * Fixed batched unit test --- readme.md | 2 +- testing/tests/TestLogFunctions.php | 78 +++++++++++++++++++----------- 2 files changed, 50 insertions(+), 30 deletions(-) diff --git a/readme.md b/readme.md index 4e1e7d6..e4f487a 100644 --- a/readme.md +++ b/readme.md @@ -74,7 +74,7 @@ Backup and save your contact form emails (including Contact Form 7) to your data 1. Download the repo 2. Run `composer install` 3. Run `bash ./testing/bin/install-wp-tests.sh` -4. Run `phpunit` +4. Run `./vendor/bin/phpunit` ## Found an issue, or have an idea on how we can improve? Let us know in our [GitHub tracker!](https://github.com/JWardee/wp-mail-catcher/issues) diff --git a/testing/tests/TestLogFunctions.php b/testing/tests/TestLogFunctions.php index 99f5f4d..6f1bccf 100644 --- a/testing/tests/TestLogFunctions.php +++ b/testing/tests/TestLogFunctions.php @@ -111,8 +111,8 @@ public function testCanExportSingleLog() $message = 'message'; $additionalHeaders = ['Content-type: text/html', 'cc: test1@test.com']; - $imgAttachmentId = $this->factory()->attachment->create_upload_object(__DIR__.'/../assets/img-attachment.png'); - $pdfAttachmentId = $this->factory()->attachment->create_upload_object(__DIR__.'/../assets/pdf-attachment.pdf'); + $imgAttachmentId = $this->factory()->attachment->create_upload_object(__DIR__ . '/../assets/img-attachment.png'); + $pdfAttachmentId = $this->factory()->attachment->create_upload_object(__DIR__ . '/../assets/pdf-attachment.pdf'); wp_mail($to, $subject, $message, $additionalHeaders, [ get_attached_file($imgAttachmentId), @@ -136,8 +136,8 @@ public function testCanExportSingleLog() $this->assertContains($to, $csvArray); $this->assertContains($subject, $csvArray); - $this->assertContains($additionalHeaders[0].GeneralHelper::$csvItemDelimiter.$additionalHeaders[1], $csvArray); - $this->assertContains(wp_get_attachment_url($imgAttachmentId).GeneralHelper::$csvItemDelimiter.wp_get_attachment_url($pdfAttachmentId), $csvArray); + $this->assertContains($additionalHeaders[0] . GeneralHelper::$csvItemDelimiter . $additionalHeaders[1], $csvArray); + $this->assertContains(wp_get_attachment_url($imgAttachmentId) . GeneralHelper::$csvItemDelimiter . wp_get_attachment_url($pdfAttachmentId), $csvArray); wp_delete_attachment($imgAttachmentId); wp_delete_attachment($pdfAttachmentId); @@ -154,8 +154,8 @@ public function testCanExportMultipleLogs() $message2 = 'message 2'; $additionalHeaders = ['Content-type: text/html', 'cc: test1@test.com']; - $imgAttachmentId = $this->factory()->attachment->create_upload_object(__DIR__.'/../assets/img-attachment.png'); - $pdfAttachmentId = $this->factory()->attachment->create_upload_object(__DIR__.'/../assets/pdf-attachment.pdf'); + $imgAttachmentId = $this->factory()->attachment->create_upload_object(__DIR__ . '/../assets/img-attachment.png'); + $pdfAttachmentId = $this->factory()->attachment->create_upload_object(__DIR__ . '/../assets/pdf-attachment.pdf'); wp_mail($to1, $subject1, $message1, $additionalHeaders, [ get_attached_file($imgAttachmentId), @@ -189,8 +189,8 @@ public function testCanExportMultipleLogs() $this->assertContains($to2, $csvArray); $this->assertContains($subject2, $csvArray); $this->assertContains($message2, $csvArray); - $this->assertContains($additionalHeaders[0].GeneralHelper::$csvItemDelimiter.$additionalHeaders[1], $csvArray); - $this->assertContains(wp_get_attachment_url($imgAttachmentId).GeneralHelper::$csvItemDelimiter.wp_get_attachment_url($pdfAttachmentId), $csvArray); + $this->assertContains($additionalHeaders[0] . GeneralHelper::$csvItemDelimiter . $additionalHeaders[1], $csvArray); + $this->assertContains(wp_get_attachment_url($imgAttachmentId) . GeneralHelper::$csvItemDelimiter . wp_get_attachment_url($pdfAttachmentId), $csvArray); wp_delete_attachment($imgAttachmentId); wp_delete_attachment($pdfAttachmentId); @@ -201,39 +201,58 @@ public function testCanExportLogsInBatches() $numberOfBatches = 2; $totalNumberOfLogs = 10; $logsPerBatch = $totalNumberOfLogs / $numberOfBatches; - $imgAttachmentId = $this->factory()->attachment->create_upload_object(__DIR__.'/../assets/img-attachment.png'); - $pdfAttachmentId = $this->factory()->attachment->create_upload_object(__DIR__.'/../assets/pdf-attachment.pdf'); + $imgAttachmentId = $this->factory()->attachment->create_upload_object(__DIR__ . '/../assets/img-attachment.png'); + $pdfAttachmentId = $this->factory()->attachment->create_upload_object(__DIR__ . '/../assets/pdf-attachment.pdf'); for ($i = 0; $i < $totalNumberOfLogs; $i++) { - wp_mail('test'.$i.'@test.com', 'subject '.$i, 'message '.$i, - ['Content-type: text/html', 'cc: test'.($i + 1).'@test.com'], [ + wp_mail( + 'test' . $i . '@test.com', + 'subject ' . $i, + 'message ' . $i, + ['Content-type: text/html', 'cc: test' . ($i + 1) . '@test.com'], + [ get_attached_file($imgAttachmentId), get_attached_file($pdfAttachmentId) - ]); + ] + ); } + for ($i = 0; $i < $numberOfBatches; $i++) { $batch = wp_list_pluck(Logs::get([ 'posts_per_page' => $logsPerBatch, 'paged' => ($i + 1), ]), 'id'); - $csvString = $export = Mail::export($batch, false); - $csvArray = explode(',', $csvString); + $csvString = Mail::export($batch, false); + + // Split each csv line into an array + $csvArrays = explode(PHP_EOL, $csvString); + + // Remove csv headings + array_shift($csvArrays); + + // Concat csv arrays into a single array + $csvArray = explode(",", implode(",", $csvArrays)); + // Format values ready for assertions array_walk($csvArray, function (&$element) { $element = str_replace('"', '', $element); $element = str_replace(["\r", "\n", '"'], '', $element); }); - for ($j = ($i * $logsPerBatch); $j < ($i * $logsPerBatch); $j++) { - $this->assertContains('test'.$j.'@test.com', $csvArray); - $this->assertContains('subject '.$j, $csvArray); - $this->assertContains('message '.$j, $csvArray); - $this->assertContains('Content-type: text/html'.GeneralHelper::$csvItemDelimiter.'cc: test'.($j + 1).'@test.com', - $csvArray); - $this->assertContains(wp_get_attachment_url($imgAttachmentId).GeneralHelper::$csvItemDelimiter.wp_get_attachment_url($pdfAttachmentId), - $csvArray); + for ($j = ($i * $logsPerBatch); $j < ((($i + 1) * $logsPerBatch) - 1); $j++) { + $this->assertContains('test' . $j . '@test.com', $csvArray); + $this->assertContains('subject ' . $j, $csvArray); + $this->assertContains('message ' . $j, $csvArray); + $this->assertContains( + 'Content-type: text/html' . GeneralHelper::$csvItemDelimiter . 'cc: test' . ($j + 1) . '@test.com', + $csvArray + ); + $this->assertContains( + wp_get_attachment_url($imgAttachmentId) . GeneralHelper::$csvItemDelimiter . wp_get_attachment_url($pdfAttachmentId), + $csvArray + ); } } @@ -285,10 +304,11 @@ public function testMailSuccessActionTriggered() $actionWasCalled = true; }; - add_action(GeneralHelper::$actionNameSpace.'_mail_success', $func); + add_action(GeneralHelper::$actionNameSpace . '_mail_success', $func); wp_mail('test@test.com', 'subject', $message); + $this->assertTrue($actionWasCalled); - remove_action(GeneralHelper::$actionNameSpace.'_mail_success', $func); + remove_action(GeneralHelper::$actionNameSpace . '_mail_success', $func); } public function testMailFailedActionTriggered() @@ -301,11 +321,11 @@ public function testMailFailedActionTriggered() $actionWasCalled = true; }; - add_action(GeneralHelper::$actionNameSpace.'_mail_failed', $func); + add_action(GeneralHelper::$actionNameSpace . '_mail_failed', $func); wp_mail('', 'subject', $message); $this->assertTrue($actionWasCalled); - remove_action(GeneralHelper::$actionNameSpace.'_mail_failed', $func); + remove_action(GeneralHelper::$actionNameSpace . '_mail_failed', $func); } public function testCanAddTimeIntervalViaFilter() @@ -315,7 +335,7 @@ public function testCanAddTimeIntervalViaFilter() 'test' => 123 ]; - $func = function($deletionIntervals) use ($newDeletionInterval) { + $func = function ($deletionIntervals) use ($newDeletionInterval) { return array_merge($deletionIntervals, $newDeletionInterval); }; @@ -348,7 +368,7 @@ public function testExpiredMailIsDeleted() public function testDoesUnevenHeaderKeysAndValuesCorrectItself() { Mail::add( - ['to', 'Content-Type: text/html', 'foo: bar'], + ['to', 'Content-Type: text/html', 'foo: bar'], [''], [], '', From 45c659d0fdac1039e8b9e23b502971711748b079 Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 12 Apr 2022 20:56:06 +0100 Subject: [PATCH 06/18] * Updated readme --- readme.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index c6f7719..ab39154 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: mail logging, email log, email logger, logging, email logging, mail, crm Requires at least: 4.7 Tested up to: 5.9 Requires PHP: 7.2 -Stable tag: 1.5.4 +Stable tag: 2.0.0 License: GNU General Public License v3.0 License URI: https://raw.githubusercontent.com/JWardee/wp-mail-catcher/master/LICENSE Donate link: https://paypal.me/jamesmward @@ -93,6 +93,10 @@ Great! Please leave a note in our (GitHub tracker) == Changelog == += 2.0.0 = + +- Deprecation: Increased minimal PHP version to 7.2 + = 1.5.4 = - Fix: Auto delete wasn't always deleting Logs From ebcf18a9426e1531ce135f9b2c1e351d423cd2eb Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 12 Apr 2022 21:04:59 +0100 Subject: [PATCH 07/18] * Bump version number * Update grunt * Added dependabot dependencies recommendations in lock file --- WpMailCatcher.php | 2 +- build/grunt/package-lock.json | 1157 ++++----------------------------- build/grunt/package.json | 2 +- 3 files changed, 111 insertions(+), 1050 deletions(-) diff --git a/WpMailCatcher.php b/WpMailCatcher.php index e32d8f2..e38f572 100644 --- a/WpMailCatcher.php +++ b/WpMailCatcher.php @@ -6,7 +6,7 @@ Domain Path: /languages Description: Logging your mail will stop you from ever losing your emails again! This fast, lightweight plugin (under 140kb in size!) is also useful for debugging or backing up your messages. Author: James Ward -Version: 1.5.4 +Version: 2.0.0 Author URI: https://jamesward.io Donate link: https://paypal.me/jamesmward */ diff --git a/build/grunt/package-lock.json b/build/grunt/package-lock.json index 2ba1646..95c6181 100644 --- a/build/grunt/package-lock.json +++ b/build/grunt/package-lock.json @@ -51,24 +51,6 @@ "sprintf-js": "~1.0.2" } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, "array-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", @@ -81,28 +63,10 @@ "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", "dev": true }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, "async": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", - "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", "dev": true }, "autoprefixer": { @@ -162,61 +126,6 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "base64-js": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", @@ -282,32 +191,12 @@ } }, "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" } }, "brotli": { @@ -334,23 +223,6 @@ "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=", "dev": true }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, "caller-callsite": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", @@ -426,29 +298,6 @@ } } }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "clean-css": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", @@ -469,16 +318,6 @@ "q": "^1.1.2" } }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, "color": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", @@ -524,12 +363,6 @@ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", "dev": true }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -541,12 +374,6 @@ "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=", "dev": true }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, "cosmiconfig": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", @@ -827,12 +654,6 @@ "ms": "^2.1.1" } }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -842,47 +663,6 @@ "object-keys": "^1.0.12" } }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "detect-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", @@ -1046,56 +826,6 @@ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "dev": true }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, "expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", @@ -1111,92 +841,6 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "faye-websocket": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", @@ -1217,26 +861,12 @@ } }, "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "to-regex-range": "^5.0.1" } }, "find-up": { @@ -1311,15 +941,6 @@ "resolved": "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz", "integrity": "sha1-VQKYfchxS+M5IJfzLgBxyd7gfPY=" }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, "fs-extra": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.6.4.tgz", @@ -1366,16 +987,10 @@ "globule": "^1.0.0" } }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, "getobject": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.1.tgz", - "integrity": "sha512-tj18lLe+917AACr6BdVoUuHnBPTVd9BEJp1vxnMZ58ztNvuxz9Ufa+wf3g37tlGITH35jggwZ2d9lcgHJJgXfQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.2.tgz", + "integrity": "sha512-2zblDBaFcb3rB4rF77XVnuINOE2h2k/OnqXAiy0IrTxUfV1iFp3la33oAQVY9pCpWU268WFYVt2t71hlMuLsOg==", "dev": true }, "glob": { @@ -1454,9 +1069,9 @@ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" }, "grunt": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.3.0.tgz", - "integrity": "sha512-6ILlMXv11/4cxuhSMfSU+SfvbxrPuqZrAtLN64+tZpQ3DAKfSQPQHRbTjSbdtxfyQhGZPtN0bDZJ/LdCM5WXXA==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.5.2.tgz", + "integrity": "sha512-XCtfaIu72OyDqK24MjWiGC9SwlkuhkS1mrULr1xzuJ2XqAFhP3ZAchZGHJeSCY6mkaOXU4F7SbmmCF7xIVoC9w==", "dev": true, "requires": { "dateformat": "~3.0.3", @@ -1464,10 +1079,10 @@ "exit": "~0.1.2", "findup-sync": "~0.3.0", "glob": "~7.1.6", - "grunt-cli": "~1.3.2", - "grunt-known-options": "~1.1.0", + "grunt-cli": "~1.4.3", + "grunt-known-options": "~2.0.0", "grunt-legacy-log": "~3.0.0", - "grunt-legacy-util": "~2.0.0", + "grunt-legacy-util": "~2.0.1", "iconv-lite": "~0.4.13", "js-yaml": "~3.14.0", "minimatch": "~3.0.4", @@ -1477,16 +1092,16 @@ }, "dependencies": { "grunt-cli": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.3.2.tgz", - "integrity": "sha512-8OHDiZZkcptxVXtMfDxJvmN7MVJNE8L/yIcPb4HB7TlyFD1kDvjHrb62uhySsU14wJx9ORMnTuhRMQ40lH/orQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", + "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", "dev": true, "requires": { - "grunt-known-options": "~1.1.0", + "grunt-known-options": "~2.0.0", "interpret": "~1.1.0", - "liftoff": "~2.5.0", + "liftup": "~3.0.1", "nopt": "~4.0.1", - "v8flags": "~3.1.1" + "v8flags": "~3.2.0" }, "dependencies": { "nopt": { @@ -1684,9 +1299,9 @@ } }, "grunt-known-options": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz", - "integrity": "sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", + "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", "dev": true }, "grunt-legacy-log": { @@ -1721,9 +1336,9 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -1904,38 +1519,6 @@ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", "dev": true }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "hex-color-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", @@ -2048,38 +1631,12 @@ "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", "dev": true }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "is-callable": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", @@ -2101,59 +1658,20 @@ } }, "is-core-module": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", - "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", "dev": true, "requires": { "has": "^1.0.3" } }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "is-date-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", "dev": true }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, "is-directory": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", @@ -2166,12 +1684,6 @@ "integrity": "sha1-6EnEDw4YpoU8DWtrrCTvHyxznms=", "dev": true }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -2179,33 +1691,19 @@ "dev": true }, "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "^2.1.1" } }, "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true }, "is-obj": { "version": "2.0.0", @@ -2309,12 +1807,6 @@ "integrity": "sha1-XrnK2W2cPR04TyZ5L5UyThWC7dg=", "dev": true }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2404,31 +1896,31 @@ } } }, - "liftoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", - "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", + "liftup": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", + "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", "dev": true, "requires": { - "extend": "^3.0.0", - "findup-sync": "^2.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", + "extend": "^3.0.2", + "findup-sync": "^4.0.0", + "fined": "^1.2.0", + "flagged-respawn": "^1.0.1", "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" + "object.map": "^1.0.1", + "rechoir": "^0.7.0", + "resolve": "^1.19.0" }, "dependencies": { "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", "dev": true, "requires": { "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", "resolve-dir": "^1.0.1" } } @@ -2496,15 +1988,6 @@ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, "math-expression-evaluator": { "version": "1.2.22", "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.22.tgz", @@ -2561,24 +2044,13 @@ "dev": true }, "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "minimatch": { @@ -2594,27 +2066,6 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, "mkdirp": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", @@ -2632,25 +2083,6 @@ "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", "dev": true }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, "ncp": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", @@ -2708,37 +2140,6 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "object-inspect": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", @@ -2751,15 +2152,6 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, "object.assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", @@ -2906,12 +2298,6 @@ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", "dev": true }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -2944,6 +2330,12 @@ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", "dev": true }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, "pixrem": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pixrem/-/pixrem-4.0.1.tgz", @@ -2983,12 +2375,6 @@ "find-up": "^2.1.0" } }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, "postcss": { "version": "8.2.10", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.10.tgz", @@ -4251,12 +3637,12 @@ } }, "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", "dev": true, "requires": { - "resolve": "^1.1.6" + "resolve": "^1.9.0" } }, "reduce-css-calc": { @@ -4284,36 +3670,15 @@ "balanced-match": "^1.0.0" } }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "resolve-dir": { @@ -4332,18 +3697,6 @@ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", "dev": true }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, "rgb-hex": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/rgb-hex/-/rgb-hex-2.1.0.tgz", @@ -4438,15 +3791,6 @@ "integrity": "sha1-PnZyPjjf3aE8mx0poeB//uSzC1c=", "dev": true }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -4459,29 +3803,6 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, "simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -4499,167 +3820,11 @@ } } }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -4672,27 +3837,6 @@ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", "dev": true }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "string-template": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", @@ -4789,6 +3933,12 @@ "has-flag": "^3.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, "svgo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", @@ -4847,46 +3997,13 @@ "qs": "^6.4.0" } }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "^7.0.0" } }, "uglify-js": { @@ -4902,25 +4019,21 @@ "dev": true }, "underscore.string": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz", - "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.6.tgz", + "integrity": "sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ==", "dev": true, "requires": { - "sprintf-js": "^1.0.3", + "sprintf-js": "^1.1.1", "util-deprecate": "^1.0.2" - } - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" + }, + "dependencies": { + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + } } }, "uniq": { @@ -4946,64 +4059,12 @@ "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", "dev": true }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, "uri-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", "dev": true }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -5023,9 +4084,9 @@ } }, "v8flags": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz", - "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", "dev": true, "requires": { "homedir-polyfill": "^1.0.1" diff --git a/build/grunt/package.json b/build/grunt/package.json index cbeb9d4..89a0e84 100644 --- a/build/grunt/package.json +++ b/build/grunt/package.json @@ -13,7 +13,7 @@ "autoprefixer": "^9.4.3", "css-mqpacker": "^7.0.0", "cssnano": "^4.1.8", - "grunt": "^1.3.0", + "grunt": "^1.5.2", "grunt-contrib-clean": "^2.0.0", "grunt-contrib-concat": "^1.0.1", "grunt-contrib-cssmin": "^3.0.0", From d3f67f804a00c99dc4ef9008f734b23f42d4867d Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 12 Apr 2022 21:12:28 +0100 Subject: [PATCH 08/18] * Fix for #131 --- build/scss/admin.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/scss/admin.scss b/build/scss/admin.scss index 7e4953d..d57eb70 100644 --- a/build/scss/admin.scss +++ b/build/scss/admin.scss @@ -201,7 +201,8 @@ width: 600px; &.is-html { - width: 800px; + width: 80%; + max-width: 800px; } .html-preview { From b4c88f9ca6fad2ac217976942c633b51ee7b9e03 Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 12 Apr 2022 21:12:37 +0100 Subject: [PATCH 09/18] * Recompile --- build/grunt/package.json | 2 +- languages/WpMailCatcher.pot | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build/grunt/package.json b/build/grunt/package.json index 89a0e84..752a371 100644 --- a/build/grunt/package.json +++ b/build/grunt/package.json @@ -1,6 +1,6 @@ { "name": "WpMailCatcher", - "version": "1.5.4", + "version": "2.0.0", "lang_po_directory": "../../languages", "build_directory": "./..", "dist_directory": "../../assets", diff --git a/languages/WpMailCatcher.pot b/languages/WpMailCatcher.pot index 6c5a3f7..e944ab6 100644 --- a/languages/WpMailCatcher.pot +++ b/languages/WpMailCatcher.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: WpMailCatcher 1.5.0\n" +"Project-Id-Version: WpMailCatcher 2.0.0\n" "Report-Msgid-Bugs-To: wordpress@jamesward.io\n" -"POT-Creation-Date: 2021-02-05 15:29+0000\n" +"POT-Creation-Date: 2022-04-12 21:11+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: ../../src/Bootstrap.php:54 ../../src/Bootstrap.php:87 +#: ../../src/Bootstrap.php:51 ../../src/Bootstrap.php:84 msgid "Settings" msgstr "" @@ -252,6 +252,7 @@ msgid "No" msgstr "" #: ../../src/Views/Settings.php:98 +#, php-format msgid "Yes - delete messages that are over %s old" msgstr "" From a592c0fa50601c03ed59d1233e8cfd341dd6f904 Mon Sep 17 00:00:00 2001 From: James Ward Date: Mon, 18 Apr 2022 19:22:36 +0100 Subject: [PATCH 10/18] * Added database upgrade system --- languages/WpMailCatcher.pot | 25 ++-- src/Bootstrap.php | 207 +++++++++++++++-------------- src/DatabaseUpgradeManager.php | 82 ++++++++++++ src/GeneralHelper.php | 1 + src/Models/Logs.php | 2 +- src/Views/Log.php | 14 ++ src/Views/NewMessageModal.php | 2 +- testing/tests/TestEmails.php | 30 ++++- testing/tests/TestLogFunctions.php | 4 +- 9 files changed, 253 insertions(+), 114 deletions(-) create mode 100644 src/DatabaseUpgradeManager.php diff --git a/languages/WpMailCatcher.pot b/languages/WpMailCatcher.pot index e944ab6..7efffd7 100644 --- a/languages/WpMailCatcher.pot +++ b/languages/WpMailCatcher.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: WpMailCatcher 2.0.0\n" "Report-Msgid-Bugs-To: wordpress@jamesward.io\n" -"POT-Creation-Date: 2022-04-12 21:11+0100\n" +"POT-Creation-Date: 2022-04-18 19:18+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -29,7 +29,7 @@ msgstr "" msgid "Once a month" msgstr "" -#: ../../src/GeneralHelper.php:218 +#: ../../src/GeneralHelper.php:219 #, php-format msgctxt "%s = human-readable time difference" msgid "%s" @@ -103,11 +103,16 @@ msgstr "" msgid "If you've found this useful - please rate us!" msgstr "" -#: ../../src/Views/Log.php:19 +#: ../../src/Views/Log.php:22 msgid "logs" msgstr "" -#: ../../src/Views/Log.php:25 +#: ../../src/Views/Log.php:28 +#, php-format +msgid "Click here to upgrade your database" +msgstr "" + +#: ../../src/Views/Log.php:41 #, php-format msgid "" "You have over %s messages stored and auto-" @@ -115,27 +120,27 @@ msgid "" "please either allow auto-delete or delete some logs." msgstr "" -#: ../../src/Views/Log.php:37 +#: ../../src/Views/Log.php:53 msgid "New Message" msgstr "" -#: ../../src/Views/Log.php:42 ../../src/Views/Log.php:47 +#: ../../src/Views/Log.php:58 ../../src/Views/Log.php:63 msgid "Export all messages" msgstr "" -#: ../../src/Views/Log.php:56 +#: ../../src/Views/Log.php:72 msgid "All" msgstr "" -#: ../../src/Views/Log.php:62 +#: ../../src/Views/Log.php:78 msgid "Successful" msgstr "" -#: ../../src/Views/Log.php:68 +#: ../../src/Views/Log.php:84 msgid "Failed" msgstr "" -#: ../../src/Views/Log.php:74 +#: ../../src/Views/Log.php:90 msgid "Search Logs" msgstr "" diff --git a/src/Bootstrap.php b/src/Bootstrap.php index 5bc862c..eda8a91 100644 --- a/src/Bootstrap.php +++ b/src/Bootstrap.php @@ -95,112 +95,120 @@ public function registerPages() public function route() { - if (isset($_GET['page'])) { - if ($_GET['page'] == GeneralHelper::$adminPageSlug) { - if (current_user_can(Settings::get('default_view_role'))) { - - /** Export all messages */ - if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'export-all') { - if (!wp_verify_nonce($_REQUEST['_wpnonce'], 'bulk-logs')) { - wp_die(GeneralHelper::$failedNonceMessage); - } - - $args = Logs::getTotalAmount() > GeneralHelper::$logLimitBeforeWarning ? [ - 'posts_per_page' => $_REQUEST['posts_per_page'], - 'paged' => $_REQUEST['paged'], - ] : [ - 'posts_per_page' => -1 - ]; - - Mail::export(wp_list_pluck( - Logs::get($args), - 'id' - )); - } - - /** Export message(s) */ - if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'export' || - isset($_REQUEST['action2']) && $_REQUEST['action2'] == 'export') { - if (!wp_verify_nonce($_REQUEST['_wpnonce'], 'bulk-logs')) { - wp_die(GeneralHelper::$failedNonceMessage); - } - - Mail::export($_REQUEST['id']); - } - - /** Resend message(s) */ - if (((isset($_REQUEST['action']) && $_REQUEST['action'] == 'resend') || (isset($_REQUEST['action2']) && $_REQUEST['action2'] == 'resend')) && - isset($_REQUEST['id']) && !empty($_REQUEST['id'])) { - if (!wp_verify_nonce($_REQUEST['_wpnonce'], 'bulk-logs')) { - wp_die(GeneralHelper::$failedNonceMessage); - } - - Mail::resend($_REQUEST['id']); - GeneralHelper::redirectToThisHomeScreen(); - } - - /** Delete message(s) */ - if (((isset($_REQUEST['action']) && $_REQUEST['action'] == 'delete') || (isset($_REQUEST['action2']) && $_REQUEST['action2'] == 'delete')) && - isset($_REQUEST['id']) && !empty($_REQUEST['id'])) { - if (!wp_verify_nonce($_REQUEST['_wpnonce'], 'bulk-logs')) { - wp_die(GeneralHelper::$failedNonceMessage); - } - - Logs::delete($_REQUEST['id']); - GeneralHelper::redirectToThisHomeScreen(); - } - - /** Send mail */ - if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'new_mail') { - if (!wp_verify_nonce($_REQUEST['_wpnonce'], 'new_mail')) { - wp_die(GeneralHelper::$failedNonceMessage); - } - - Mail::add( - $_POST['header_keys'], - $_POST['header_values'], - $_POST['attachment_ids'], - $_POST['subject'], - $_POST['message'] - ); - GeneralHelper::redirectToThisHomeScreen(); - } - - if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'single_mail' && - isset($_REQUEST['id']) && !empty($_REQUEST['id'])) { - $log = Logs::get(['post__in' => [$_REQUEST['id']]])[0]; - $view = GeneralHelper::$pluginViewDirectory; - $view .= $log['is_html'] == true ? '/HtmlMessage.php' : '/TextMessage.php'; - - require $view; - exit; - } + if (!isset($_GET['page']) || $_GET['page'] !== GeneralHelper::$adminPageSlug) { + return; + } + + if (current_user_can(Settings::get('default_view_role'))) { + /** Perform database upgrade */ + if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'upgrade-database') { + $dbUpgradeManager = DatabaseUpgradeManager::getInstance(); + $dbUpgradeManager->doUpgrade(); + GeneralHelper::redirectToThisHomeScreen(); + } + + /** Export all messages */ + if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'export-all') { + if (!wp_verify_nonce($_REQUEST['_wpnonce'], 'bulk-logs')) { + wp_die(GeneralHelper::$failedNonceMessage); + } + + $args = Logs::getTotalAmount() > GeneralHelper::$logLimitBeforeWarning ? [ + 'posts_per_page' => $_REQUEST['posts_per_page'], + 'paged' => $_REQUEST['paged'], + ] : [ + 'posts_per_page' => -1 + ]; + + Mail::export(wp_list_pluck( + Logs::get($args), + 'id' + )); + } + + /** Export message(s) */ + if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'export' || + isset($_REQUEST['action2']) && $_REQUEST['action2'] == 'export') { + if (!wp_verify_nonce($_REQUEST['_wpnonce'], 'bulk-logs')) { + wp_die(GeneralHelper::$failedNonceMessage); } - if (current_user_can(Settings::get('default_settings_role'))) { - if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'update_settings') { - if (!wp_verify_nonce($_REQUEST['_wpnonce'], 'update_settings')) { - wp_die(GeneralHelper::$failedNonceMessage); - } + Mail::export($_REQUEST['id']); + } - $_POST['auto_delete'] = $_POST['auto_delete'] === 'true'; + /** Resend message(s) */ + if (((isset($_REQUEST['action']) && $_REQUEST['action'] == 'resend') || (isset($_REQUEST['action2']) && $_REQUEST['action2'] == 'resend')) && + isset($_REQUEST['id']) && !empty($_REQUEST['id'])) { + if (!wp_verify_nonce($_REQUEST['_wpnonce'], 'bulk-logs')) { + wp_die(GeneralHelper::$failedNonceMessage); + } - CronManager::getInstance()->clearTasks(); + Mail::resend($_REQUEST['id']); + GeneralHelper::redirectToThisHomeScreen(); + } - $updateSuccess = Settings::update([ - 'default_view_role' => $_POST['default_view_role'], - 'default_settings_role' => $_POST['default_settings_role'], - 'auto_delete' => $_POST['auto_delete'], - 'timescale' => $_POST['auto_delete'] == true ? $_POST['timescale'] : null, - ]); + /** Delete message(s) */ + if (((isset($_REQUEST['action']) && $_REQUEST['action'] == 'delete') || (isset($_REQUEST['action2']) && $_REQUEST['action2'] == 'delete')) && + isset($_REQUEST['id']) && !empty($_REQUEST['id'])) { + if (!wp_verify_nonce($_REQUEST['_wpnonce'], 'bulk-logs')) { + wp_die(GeneralHelper::$failedNonceMessage); + } + + Logs::delete($_REQUEST['id']); + GeneralHelper::redirectToThisHomeScreen(); + } - GeneralHelper::redirectToThisHomeScreen([ - 'update_success' => $updateSuccess, - 'page' => GeneralHelper::$adminPageSlug . '-settings' - ]); - } + /** Send mail */ + if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'new_mail') { + if (!wp_verify_nonce($_REQUEST['_wpnonce'], 'new_mail')) { + wp_die(GeneralHelper::$failedNonceMessage); } + + Mail::add( + $_POST['header_keys'], + $_POST['header_values'], + $_POST['attachment_ids'], + $_POST['subject'], + $_POST['message'] + ); + GeneralHelper::redirectToThisHomeScreen(); + } + + if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'single_mail' && + isset($_REQUEST['id']) && !empty($_REQUEST['id'])) { + $log = Logs::get(['post__in' => [$_REQUEST['id']]])[0]; + $view = GeneralHelper::$pluginViewDirectory; + $view .= $log['is_html'] == true ? '/HtmlMessage.php' : '/TextMessage.php'; + + require $view; + exit; + } + } + + if (current_user_can(Settings::get('default_settings_role'))) { + if (!isset($_REQUEST['action']) || $_REQUEST['action'] !== 'update_settings') { + return; } + + if (!wp_verify_nonce($_REQUEST['_wpnonce'], 'update_settings')) { + wp_die(GeneralHelper::$failedNonceMessage); + } + + $_POST['auto_delete'] = $_POST['auto_delete'] === 'true'; + + CronManager::getInstance()->clearTasks(); + + $updateSuccess = Settings::update([ + 'default_view_role' => $_POST['default_view_role'], + 'default_settings_role' => $_POST['default_settings_role'], + 'auto_delete' => $_POST['auto_delete'], + 'timescale' => $_POST['auto_delete'] == true ? $_POST['timescale'] : null, + ]); + + GeneralHelper::redirectToThisHomeScreen([ + 'update_success' => $updateSuccess, + 'page' => GeneralHelper::$adminPageSlug . '-settings' + ]); } } @@ -242,6 +250,9 @@ public function install($newSite = null) if ($newSite != null) { restore_current_blog(); } + + $dbUpgradeManager = DatabaseUpgradeManager::getInstance(); + $dbUpgradeManager->doUpgrade(); } static public function deactivate() diff --git a/src/DatabaseUpgradeManager.php b/src/DatabaseUpgradeManager.php new file mode 100644 index 0000000..b2bdfa9 --- /dev/null +++ b/src/DatabaseUpgradeManager.php @@ -0,0 +1,82 @@ + 'doV2Upgrade', + ]; + + private function __construct() + { + $this->dbVersion = Settings::get('db_version'); + } + + public static function getInstance() + { + if (self::$instance == false) { + self::$instance = new DatabaseUpgradeManager(); + } + + return self::$instance; + } + + + public function isUpgradeRequired() + { + foreach ($this->upgradePaths as $version => $method) { + if ($this->dbVersion < $version) { + return true; + } + } + + return false; + } + + public function doUpgrade() + { + if (!self::isUpgradeRequired()) { + return; + } + + foreach ($this->upgradePaths as $version => $method) { + if ($this->dbVersion < $version) { + $this->{$method}(); + } + } + + Settings::update(['db_version' => GeneralHelper::$pluginVersion]); + } + + private function doV2Upgrade() + { + global $wpdb; + + // dbDelta creates a diff between the table schemas, and executes + // the necessary SQL so they match. In this case we add the column + // is_html and default it to false + $sql = "CREATE TABLE " . $wpdb->prefix . GeneralHelper::$tableName . " ( + id int NOT NULL AUTO_INCREMENT, + time int NOT NULL, + email_to text DEFAULT NULL, + subject text DEFAULT NULL, + message text DEFAULT NULL, + backtrace_segment text NOT NULL, + status bool DEFAULT 1 NOT NULL, + error text DEFAULT NULL, + attachments text DEFAULT NULL, + additional_headers text DEFAULT NULL, + is_html bool DEFAULT 0, + PRIMARY KEY (id) + ) " . $wpdb->get_charset_collate() . ";"; + + require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); + dbDelta($sql); + } +} diff --git a/src/GeneralHelper.php b/src/GeneralHelper.php index 64ba837..b90c8f4 100644 --- a/src/GeneralHelper.php +++ b/src/GeneralHelper.php @@ -27,6 +27,7 @@ class GeneralHelper static public $namespacePrefix; static public $reviewLink; static public $actionNameSpace; + static public $htmlEmailHeader = 'Content-Type: text/html;'; static public function setSettings() { diff --git a/src/Models/Logs.php b/src/Models/Logs.php index 84a0067..ccdee1e 100644 --- a/src/Models/Logs.php +++ b/src/Models/Logs.php @@ -142,7 +142,7 @@ static private function dbResultTransform($results, $args = []) $result['timestamp'] = $result['time']; $result['time'] = $args['date_time_format'] == 'human' ? GeneralHelper::getHumanReadableTimeFromNow($result['timestamp']) : date($args['date_time_format'], $result['timestamp']); - $result['is_html'] = GeneralHelper::doesArrayContainSubString($result['additional_headers'], 'text/html'); + $result['is_html'] = GeneralHelper::doesArrayContainSubString($result['additional_headers'], GeneralHelper::$htmlEmailHeader); $result['email_from'] = self::getEmailFrom($result); $result['message'] = stripslashes(htmlspecialchars_decode($result['message'])); diff --git a/src/Views/Log.php b/src/Views/Log.php index d066502..747efd0 100644 --- a/src/Views/Log.php +++ b/src/Views/Log.php @@ -4,6 +4,7 @@ use WpMailCatcher\Models\Settings; +$dbUpgradeManager = DatabaseUpgradeManager::getInstance(); $settings = Settings::get(); $logs = MailAdminTable::getInstance(); $logs->prepare_items(); @@ -18,6 +19,19 @@

WP Mail Catcher -

+ isUpgradeRequired()) : ?> +
+

+ here to upgrade your database', + 'WpMailCatcher'), + '?page=' . GeneralHelper::$adminPageSlug . '&action=upgrade-database' + ); + ?> +

+
+ + totalItems > GeneralHelper::$logLimitBeforeWarning && $settings['auto_delete'] == false) : ?>

diff --git a/src/Views/NewMessageModal.php b/src/Views/NewMessageModal.php index b012ca5..ad53648 100644 --- a/src/Views/NewMessageModal.php +++ b/src/Views/NewMessageModal.php @@ -33,7 +33,7 @@

- diff --git a/testing/tests/TestEmails.php b/testing/tests/TestEmails.php index 47d599f..e685d03 100644 --- a/testing/tests/TestEmails.php +++ b/testing/tests/TestEmails.php @@ -1,5 +1,6 @@ factory()->attachment->create_upload_object(__DIR__ . '/../assets/img-attachment.png'); $pdfAttachmentId = $this->factory()->attachment->create_upload_object(__DIR__ . '/../assets/pdf-attachment.pdf'); @@ -30,6 +31,7 @@ public function testMail() $this->assertEquals($to, $emailLogs[0]['email_to']); $this->assertEquals($subject, $emailLogs[0]['subject']); $this->assertEquals($message, $emailLogs[0]['message']); + $this->assertEquals(true, $emailLogs[0]['is_html']); $this->assertEquals($additionalHeaders[0], $emailLogs[0]['additional_headers'][0]); $this->assertEquals($additionalHeaders[1], $emailLogs[0]['additional_headers'][1]); @@ -56,9 +58,33 @@ public function testIncorrectTos() $this->assertFalse(Logs::get()[0]['status']); } + public function testHtmlEmailSetViaFilter() + { + $contentTypeFilterPriority = 9999; + $updateContentType = function($contentType) { + return 'text/html'; + }; + + add_filter('wp_mail_content_type', $updateContentType, $contentTypeFilterPriority); + // add_action('phpmailer_init', function($phpmailer) { + // print_r('hello from action'); + // print_r($phpmailer->getMailMIME()); + // // exit; + // }); + + // Send an email without explicitly setting the html header + wp_mail('test@test.com', 'subject', 'message'); + + // print_r(Logs::get()[0]['is_html'] ? 'true' : 'false'); + // exit; + remove_filter('wp_mail_content_type', $updateContentType, $contentTypeFilterPriority); + + $this->assertTrue(Logs::get()[0]['is_html']); + } + public function testHtmlEmail() { - wp_mail('test@test.com', 'subject', 'message', ['Content-Type: text/html']); + wp_mail('test@test.com', 'subject', 'message', [GeneralHelper::$htmlEmailHeader]); $this->assertTrue(Logs::get()[0]['is_html']); } diff --git a/testing/tests/TestLogFunctions.php b/testing/tests/TestLogFunctions.php index 6f1bccf..8a2bc91 100644 --- a/testing/tests/TestLogFunctions.php +++ b/testing/tests/TestLogFunctions.php @@ -368,7 +368,7 @@ public function testExpiredMailIsDeleted() public function testDoesUnevenHeaderKeysAndValuesCorrectItself() { Mail::add( - ['to', 'Content-Type: text/html', 'foo: bar'], + ['to', GeneralHelper::$htmlEmailHeader, 'foo: bar'], [''], [], '', @@ -377,7 +377,7 @@ public function testDoesUnevenHeaderKeysAndValuesCorrectItself() $logs = Logs::get(); $this->assertTrue($logs[0]['is_html']); - $this->assertEquals('Content-Type: text/html', $logs[0]['additional_headers'][0]); + $this->assertEquals(GeneralHelper::$htmlEmailHeader, $logs[0]['additional_headers'][0]); $this->assertEquals('foo: bar', $logs[0]['additional_headers'][1]); } } From 20d2d18c10a4e1933cb8b3b2b2e56cacadfaa99a Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 4 Jun 2022 15:44:35 +0100 Subject: [PATCH 11/18] * Bumped WP version compatibility * Implemented new method of handling html emails --- readme.txt | 2 +- src/Bootstrap.php | 31 +++++++++++++++--------------- src/DatabaseUpgradeManager.php | 28 +++++++++++++-------------- src/GeneralHelper.php | 2 +- src/Loggers/LogHelper.php | 25 ++++++++++++++++++++++++ src/Loggers/WpMail.php | 11 +++++++---- src/Models/Logs.php | 6 +++--- src/Models/Mail.php | 24 ++++++++++++++++++++++- src/Models/Settings.php | 3 ++- testing/tests/TestEmails.php | 11 ++--------- testing/tests/TestLogFunctions.php | 13 +++++++++---- 11 files changed, 103 insertions(+), 53 deletions(-) diff --git a/readme.txt b/readme.txt index ab39154..e93a941 100644 --- a/readme.txt +++ b/readme.txt @@ -2,7 +2,7 @@ Contributors: Wardee Tags: mail logging, email log, email logger, logging, email logging, mail, crm Requires at least: 4.7 -Tested up to: 5.9 +Tested up to: 6.0 Requires PHP: 7.2 Stable tag: 2.0.0 License: GNU General Public License v3.0 diff --git a/src/Bootstrap.php b/src/Bootstrap.php index eda8a91..15e33ff 100644 --- a/src/Bootstrap.php +++ b/src/Bootstrap.php @@ -169,7 +169,8 @@ public function route() $_POST['header_values'], $_POST['attachment_ids'], $_POST['subject'], - $_POST['message'] + $_POST['message'], + $_POST['is_html'] ); GeneralHelper::redirectToThisHomeScreen(); } @@ -229,17 +230,17 @@ public function install($newSite = null) } $sql = "CREATE TABLE IF NOT EXISTS " . $wpdb->prefix . GeneralHelper::$tableName . " ( - id int NOT NULL AUTO_INCREMENT, - time int NOT NULL, - email_to text DEFAULT NULL, - subject text DEFAULT NULL, - message text DEFAULT NULL, - backtrace_segment text NOT NULL, - status bool DEFAULT 1 NOT NULL, - error text DEFAULT NULL, - attachments text DEFAULT NULL, - additional_headers text DEFAULT NULL, - PRIMARY KEY (id) + id int NOT NULL AUTO_INCREMENT, + time int NOT NULL, + email_to text DEFAULT NULL, + subject text DEFAULT NULL, + message text DEFAULT NULL, + backtrace_segment text NOT NULL, + status bool DEFAULT 1 NOT NULL, + error text DEFAULT NULL, + attachments text DEFAULT NULL, + additional_headers text DEFAULT NULL, + PRIMARY KEY (id) ) " . $wpdb->get_charset_collate() . ";"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); @@ -247,12 +248,12 @@ public function install($newSite = null) Settings::installOptions(); + $dbUpgradeManager = DatabaseUpgradeManager::getInstance(); + $dbUpgradeManager->doUpgrade(); + if ($newSite != null) { restore_current_blog(); } - - $dbUpgradeManager = DatabaseUpgradeManager::getInstance(); - $dbUpgradeManager->doUpgrade(); } static public function deactivate() diff --git a/src/DatabaseUpgradeManager.php b/src/DatabaseUpgradeManager.php index b2bdfa9..9492f30 100644 --- a/src/DatabaseUpgradeManager.php +++ b/src/DatabaseUpgradeManager.php @@ -41,7 +41,7 @@ public function isUpgradeRequired() public function doUpgrade() { - if (!self::isUpgradeRequired()) { + if (!$this->isUpgradeRequired()) { return; } @@ -62,19 +62,19 @@ private function doV2Upgrade() // the necessary SQL so they match. In this case we add the column // is_html and default it to false $sql = "CREATE TABLE " . $wpdb->prefix . GeneralHelper::$tableName . " ( - id int NOT NULL AUTO_INCREMENT, - time int NOT NULL, - email_to text DEFAULT NULL, - subject text DEFAULT NULL, - message text DEFAULT NULL, - backtrace_segment text NOT NULL, - status bool DEFAULT 1 NOT NULL, - error text DEFAULT NULL, - attachments text DEFAULT NULL, - additional_headers text DEFAULT NULL, - is_html bool DEFAULT 0, - PRIMARY KEY (id) - ) " . $wpdb->get_charset_collate() . ";"; + id int NOT NULL AUTO_INCREMENT, + time int NOT NULL, + email_to text DEFAULT NULL, + subject text DEFAULT NULL, + message text DEFAULT NULL, + backtrace_segment text NOT NULL, + status bool DEFAULT 1 NOT NULL, + error text DEFAULT NULL, + attachments text DEFAULT NULL, + additional_headers text DEFAULT NULL, + is_html bool DEFAULT 0, + PRIMARY KEY (id) + ) " . $wpdb->get_charset_collate() . ";"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); diff --git a/src/GeneralHelper.php b/src/GeneralHelper.php index b90c8f4..04855ea 100644 --- a/src/GeneralHelper.php +++ b/src/GeneralHelper.php @@ -27,7 +27,7 @@ class GeneralHelper static public $namespacePrefix; static public $reviewLink; static public $actionNameSpace; - static public $htmlEmailHeader = 'Content-Type: text/html;'; + static public $htmlEmailHeader = 'content-type: text/html;'; static public function setSettings() { diff --git a/src/Loggers/LogHelper.php b/src/Loggers/LogHelper.php index 65f49e9..dbac67f 100644 --- a/src/Loggers/LogHelper.php +++ b/src/Loggers/LogHelper.php @@ -46,6 +46,10 @@ public function saveMail($args, $transformFunc) */ public function saveError($error) { + if ($this->id === null) { + return; + } + global $wpdb; $wpdb->update( @@ -61,6 +65,27 @@ public function saveError($error) do_action(GeneralHelper::$actionNameSpace . '_mail_failed', Logs::getFirst(['id' => $this->id])); } + public function saveIsHtml($contentType) + { + if ($this->id === null) { + return; + } + + global $wpdb; + + $wpdb->update( + $wpdb->prefix . GeneralHelper::$tableName, [ + 'is_html' => $contentType === 'text/html', + ], + ['id' => $this->id] + ); + + Cache::flush(); + + // Because this is triggered from add_filter we need to return the unmodified content type + return $contentType; + } + /** * Convert attachment ids or urls into a format to be usable * by the logs diff --git a/src/Loggers/WpMail.php b/src/Loggers/WpMail.php index 1c93b83..76712fb 100644 --- a/src/Loggers/WpMail.php +++ b/src/Loggers/WpMail.php @@ -3,8 +3,9 @@ namespace WpMailCatcher\Loggers; use WpMailCatcher\GeneralHelper; +use WpMailCatcher\Models\Settings; -class WpMail implements LoggerContract +class WpMail { use LogHelper; @@ -15,13 +16,15 @@ class WpMail implements LoggerContract public function __construct() { $priority = 999999; - add_action('wp_mail', [$this, 'recordMail'], $priority); + add_filter('wp_mail', [$this, 'recordMail'], $priority); add_action('wp_mail_failed', [$this, 'recordError'], $priority); + add_filter('wp_mail_content_type', [$this, 'saveIsHtml'], $priority); } public function recordMail($args) { - return $this->saveMail($args, [$this, 'getTransformedMailArgs']); + $this->saveMail($args, [$this, 'getTransformedMailArgs']); + return $args; } public function recordError($error) @@ -46,7 +49,7 @@ protected function getTransformedMailArgs($args) 'backtrace_segment' => json_encode($this->getBacktrace()), 'status' => 1, 'attachments' => json_encode($this->getAttachmentLocations($args['attachments'])), - 'additional_headers' => json_encode($args['headers']) + 'additional_headers' => json_encode($args['headers']), ]; } } diff --git a/src/Models/Logs.php b/src/Models/Logs.php index ccdee1e..068bfb1 100644 --- a/src/Models/Logs.php +++ b/src/Models/Logs.php @@ -44,7 +44,7 @@ static public function get($args = []) */ $defaults = [ 'orderby' => 'time', - 'posts_per_page' => GeneralHelper::$logsPerPage, + 'posts_per_page' => -1, 'paged' => 1, 'order' => 'DESC', 'date_time_format' => 'human', @@ -62,7 +62,7 @@ static public function get($args = []) array_walk_recursive($args, 'WpMailCatcher\GeneralHelper::sanitiseForQuery'); $sql = "SELECT id, time, email_to, subject, message, - status, error, backtrace_segment, attachments, + status, error, backtrace_segment, attachments, is_html, additional_headers FROM " . $wpdb->prefix . GeneralHelper::$tableName . " "; @@ -142,7 +142,7 @@ static private function dbResultTransform($results, $args = []) $result['timestamp'] = $result['time']; $result['time'] = $args['date_time_format'] == 'human' ? GeneralHelper::getHumanReadableTimeFromNow($result['timestamp']) : date($args['date_time_format'], $result['timestamp']); - $result['is_html'] = GeneralHelper::doesArrayContainSubString($result['additional_headers'], GeneralHelper::$htmlEmailHeader); + $result['is_html'] = $result['is_html'] ? (bool)$result['is_html'] : GeneralHelper::doesArrayContainSubString($result['additional_headers'], GeneralHelper::$htmlEmailHeader); $result['email_from'] = self::getEmailFrom($result); $result['message'] = stripslashes(htmlspecialchars_decode($result['message'])); diff --git a/src/Models/Mail.php b/src/Models/Mail.php index 694d83d..f31444b 100644 --- a/src/Models/Mail.php +++ b/src/Models/Mail.php @@ -6,6 +6,8 @@ class Mail { + private static $contentTypeFilterPriority = 9999; + static public function resend($ids) { $logs = Logs::get([ @@ -13,6 +15,12 @@ static public function resend($ids) ]); foreach ($logs as $log) { + $updateContentType = function($contentType) use ($log) { + return $log['is_html'] ? 'text/html' : $contentType; + }; + + add_filter('wp_mail_content_type', $updateContentType, self::$contentTypeFilterPriority); + wp_mail( $log['email_to'], $log['subject'], @@ -20,6 +28,8 @@ static public function resend($ids) $log['additional_headers'], $log['attachment_file_paths'] ); + + remove_filter('wp_mail_content_type', $updateContentType, self::$contentTypeFilterPriority); } } @@ -100,7 +110,7 @@ static private function processLogToCsv($headings, $logs) fclose($out); } - static public function add($headerKeys, $headerValues, $attachmentIds, $subject, $message) + static public function add($headerKeys, $headerValues, $attachmentIds, $subject, $message, $isHtml = false) { $tos = []; $headers = []; @@ -139,6 +149,18 @@ static public function add($headerKeys, $headerValues, $attachmentIds, $subject, $attachments[] = get_attached_file($attachment_id); } + if ($isHtml) { + $updateContentType = function() { + return 'text/html'; + }; + + add_filter('wp_mail_content_type', $updateContentType, self::$contentTypeFilterPriority); + } + wp_mail($tos, $subject, $message, $headers, $attachments); + + if ($isHtml) { + remove_filter('wp_mail_content_type', $updateContentType, self::$contentTypeFilterPriority); + } } } diff --git a/src/Models/Settings.php b/src/Models/Settings.php index 8242a2d..25ee65f 100644 --- a/src/Models/Settings.php +++ b/src/Models/Settings.php @@ -11,7 +11,8 @@ class Settings 'default_view_role' => 'manage_options', 'default_settings_role' => 'manage_options', 'auto_delete' => true, - 'timescale' => 2419200 + 'timescale' => 2419200, // 28 days + 'db_version' => '', ]; static public $defaultDeletionIntervals = [ 604800 => '1 week', diff --git a/testing/tests/TestEmails.php b/testing/tests/TestEmails.php index e685d03..b640f94 100644 --- a/testing/tests/TestEmails.php +++ b/testing/tests/TestEmails.php @@ -60,23 +60,16 @@ public function testIncorrectTos() public function testHtmlEmailSetViaFilter() { - $contentTypeFilterPriority = 9999; - $updateContentType = function($contentType) { + $contentTypeFilterPriority = 999; + $updateContentType = function() { return 'text/html'; }; add_filter('wp_mail_content_type', $updateContentType, $contentTypeFilterPriority); - // add_action('phpmailer_init', function($phpmailer) { - // print_r('hello from action'); - // print_r($phpmailer->getMailMIME()); - // // exit; - // }); // Send an email without explicitly setting the html header wp_mail('test@test.com', 'subject', 'message'); - // print_r(Logs::get()[0]['is_html'] ? 'true' : 'false'); - // exit; remove_filter('wp_mail_content_type', $updateContentType, $contentTypeFilterPriority); $this->assertTrue(Logs::get()[0]['is_html']); diff --git a/testing/tests/TestLogFunctions.php b/testing/tests/TestLogFunctions.php index 8a2bc91..001366e 100644 --- a/testing/tests/TestLogFunctions.php +++ b/testing/tests/TestLogFunctions.php @@ -306,7 +306,7 @@ public function testMailSuccessActionTriggered() add_action(GeneralHelper::$actionNameSpace . '_mail_success', $func); wp_mail('test@test.com', 'subject', $message); - + $this->assertTrue($actionWasCalled); remove_action(GeneralHelper::$actionNameSpace . '_mail_success', $func); } @@ -349,14 +349,19 @@ public function testCanAddTimeIntervalViaFilter() remove_filter($filterName, $func); } - public function testExpiredMailIsDeleted() + public function testAllExpiredMailAreDeleted() { - wp_mail('test@test.com', 'Old message - should be deleted', 'My message'); + $noOfExpiredMailToSend = 10; + + for ($i = 0; $i < $noOfExpiredMailToSend; $i++) { + wp_mail('test@test.com', 'Old message - should be deleted', 'My message'); + } + sleep(1); wp_mail('test@test.com', 'New message', 'My message'); $logs = Logs::get(); - $this->assertEquals(2, count($logs)); + $this->assertEquals($noOfExpiredMailToSend + 1, count($logs)); ExpiredLogManager::removeExpiredLogs(1); From b703f608e499578e48eba9c2ab029423146dac71 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 4 Jun 2022 16:16:10 +0100 Subject: [PATCH 12/18] * Added additional clarity to html emails in details tab * Added ability to manually trigger auto delete --- src/Bootstrap.php | 10 +++++- src/ExpiredLogManager.php | 2 +- src/Views/LogModal.php | 70 +++++++++++++++++++-------------------- src/Views/Settings.php | 12 ++++++- 4 files changed, 56 insertions(+), 38 deletions(-) diff --git a/src/Bootstrap.php b/src/Bootstrap.php index 15e33ff..f059567 100644 --- a/src/Bootstrap.php +++ b/src/Bootstrap.php @@ -179,7 +179,7 @@ public function route() isset($_REQUEST['id']) && !empty($_REQUEST['id'])) { $log = Logs::get(['post__in' => [$_REQUEST['id']]])[0]; $view = GeneralHelper::$pluginViewDirectory; - $view .= $log['is_html'] == true ? '/HtmlMessage.php' : '/TextMessage.php'; + $view .= $log['is_html'] ? '/HtmlMessage.php' : '/TextMessage.php'; require $view; exit; @@ -187,6 +187,14 @@ public function route() } if (current_user_can(Settings::get('default_settings_role'))) { + if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'trigger-auto-delete') { + ExpiredLogManager::removeExpiredLogs(); + GeneralHelper::redirectToThisHomeScreen([ + 'trigger-auto-delete-success' => true, + 'page' => GeneralHelper::$adminPageSlug . '-settings' + ]); + } + if (!isset($_REQUEST['action']) || $_REQUEST['action'] !== 'update_settings') { return; } diff --git a/src/ExpiredLogManager.php b/src/ExpiredLogManager.php index f1d728e..987900d 100644 --- a/src/ExpiredLogManager.php +++ b/src/ExpiredLogManager.php @@ -17,7 +17,7 @@ public static function removeExpiredLogs($timeInterval = null) $idsToRemove = []; $interval = $timeInterval == null ? Settings::get('timescale') : $timeInterval; - foreach (Logs::get() as $log) { + foreach (Logs::get(['ignore_cache' => true]) as $log) { if ((time() - $log['timestamp']) >= $interval) { $idsToRemove[] = $log['id']; } diff --git a/src/Views/LogModal.php b/src/Views/LogModal.php index a4b1258..9f16510 100644 --- a/src/Views/LogModal.php +++ b/src/Views/LogModal.php @@ -18,43 +18,43 @@ data-src="?page=&action=single_mail&id=">
- -

- -

+

+ + +

+ +

- -

-
-
    - -
  • - +

    +
    +
      + +
    • + - -
    • - -
    - + +
  • + +
+ - -

- -

-
-
    - -
  • - -
- + +

+ +

+
+
    + +
  • + +
@@ -73,7 +73,7 @@ class="attachment-item" - +
diff --git a/src/Views/Settings.php b/src/Views/Settings.php index 4b11c74..7c87a21 100644 --- a/src/Views/Settings.php +++ b/src/Views/Settings.php @@ -27,6 +27,16 @@ + + +
+

+ +

+
+ + +

WP Mail Catcher -

@@ -101,7 +111,7 @@

- + Trigger now', 'WpMailCatcher'), $cronJobs[0]['nextRun']); ?>

From 0658780eb58b00c8092fecb495c67e4f0d4ed311 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 4 Jun 2022 16:16:40 +0100 Subject: [PATCH 13/18] * Added additional assertions to html header formatting in tests --- testing/tests/TestEmails.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/testing/tests/TestEmails.php b/testing/tests/TestEmails.php index b640f94..6425c14 100644 --- a/testing/tests/TestEmails.php +++ b/testing/tests/TestEmails.php @@ -77,8 +77,16 @@ public function testHtmlEmailSetViaFilter() public function testHtmlEmail() { + // Test various formats wp_mail('test@test.com', 'subject', 'message', [GeneralHelper::$htmlEmailHeader]); + wp_mail('test@test.com', 'subject', 'message', ['content-type:text/html']); + wp_mail('test@test.com', 'subject', 'message', ['Content-Type: text/html']); + wp_mail('test@test.com', 'subject', 'message', ['Content-Type: text/html;']); + $this->assertTrue(Logs::get()[0]['is_html']); + $this->assertTrue(Logs::get()[1]['is_html']); + $this->assertTrue(Logs::get()[2]['is_html']); + $this->assertTrue(Logs::get()[3]['is_html']); } public function testNonHtmlEmail() From 062939e25d4a8836e677db7f53683c9cb2908f75 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 4 Jun 2022 17:08:18 +0100 Subject: [PATCH 14/18] * Message is no longer selected from the db unnecessarily --- src/MailAdminTable.php | 1 + src/Models/Logs.php | 59 ++++++++++++++++++++---------- src/Views/LogModal.php | 7 +--- testing/tests/TestLogFunctions.php | 11 ++++++ 4 files changed, 53 insertions(+), 25 deletions(-) diff --git a/src/MailAdminTable.php b/src/MailAdminTable.php index 9211159..851f3ac 100644 --- a/src/MailAdminTable.php +++ b/src/MailAdminTable.php @@ -160,6 +160,7 @@ function prepare_items() 'paged' => $this->get_pagenum(), 'post_status' => isset($_GET['post_status']) ? $_GET['post_status'] : 'any', 'posts_per_page' => $per_page, + 'column_blacklist' => ['message'] ], $_REQUEST)); $this->totalItems = Logs::getTotalAmount(); diff --git a/src/Models/Logs.php b/src/Models/Logs.php index 068bfb1..1d92d6e 100644 --- a/src/Models/Logs.php +++ b/src/Models/Logs.php @@ -51,19 +51,26 @@ static public function get($args = []) 'post_status' => 'any', 'post__in' => [], 'subject' => null, - 's' => null + 's' => null, + 'column_blacklist' => [] ]; $args = array_merge($defaults, $args); + $defaultColumns = [ + 'id', 'time', 'email_to', 'subject', 'message', + 'status', 'error', 'backtrace_segment', 'attachments', 'is_html', + 'additional_headers' + ]; + + $columnsToSelect = array_diff($defaultColumns, $args['column_blacklist']); + /** * Sanitise each value in the array */ array_walk_recursive($args, 'WpMailCatcher\GeneralHelper::sanitiseForQuery'); - $sql = "SELECT id, time, email_to, subject, message, - status, error, backtrace_segment, attachments, is_html, - additional_headers + $sql = "SELECT " . implode(',', $columnsToSelect) . " FROM " . $wpdb->prefix . GeneralHelper::$tableName . " "; $whereClause = false; @@ -101,10 +108,10 @@ static public function get($args = []) } switch ($args['post_status']) { - case ('successful') : + case ('successful'): $sql .= "status = 1 "; break; - case ('failed') : + case ('failed'): $sql .= "status = 0 "; break; } @@ -129,24 +136,38 @@ static public function get($args = []) static private function dbResultTransform($results, $args = []) { foreach ($results as &$result) { - $result['status'] = (bool)$result['status']; - $result['attachments'] = json_decode($result['attachments'], true); - $result['additional_headers'] = isset($result['additional_headers']) && !empty($result['additional_headers']) ? - json_decode($result['additional_headers'], true) : - []; $result['attachment_file_paths'] = []; - if (is_string($result['additional_headers'])) { - $result['additional_headers'] = explode(PHP_EOL, $result['additional_headers']); + if (isset($result['status'])) { + $result['status'] = (bool)$result['status']; } - $result['timestamp'] = $result['time']; - $result['time'] = $args['date_time_format'] == 'human' ? GeneralHelper::getHumanReadableTimeFromNow($result['timestamp']) : date($args['date_time_format'], $result['timestamp']); - $result['is_html'] = $result['is_html'] ? (bool)$result['is_html'] : GeneralHelper::doesArrayContainSubString($result['additional_headers'], GeneralHelper::$htmlEmailHeader); - $result['email_from'] = self::getEmailFrom($result); - $result['message'] = stripslashes(htmlspecialchars_decode($result['message'])); + if (isset($result['additional_headers'])) { + $result['additional_headers'] = json_decode($result['additional_headers'], true); + + if (is_string($result['additional_headers'])) { + $result['additional_headers'] = explode(PHP_EOL, $result['additional_headers']); + } + + $result['email_from'] = self::getEmailFrom($result); + } + + if (isset($result['time'])) { + $result['timestamp'] = $result['time']; + $result['time'] = $args['date_time_format'] == 'human' ? GeneralHelper::getHumanReadableTimeFromNow($result['timestamp']) : date($args['date_time_format'], $result['timestamp']); + } + + if (isset($result['is_html']) && isset($result['additional_headers'])) { + $result['is_html'] = $result['is_html'] ? (bool)$result['is_html'] : GeneralHelper::doesArrayContainSubString($result['additional_headers'], GeneralHelper::$htmlEmailHeader); + } + + if (isset($result['message'])) { + $result['message'] = stripslashes(htmlspecialchars_decode($result['message'])); + } if (!empty($result['attachments'])) { + $result['attachments'] = json_decode($result['attachments'], true); + foreach ($result['attachments'] as &$attachment) { if ($attachment['id'] == -1) { $attachment['note'] = GeneralHelper::$attachmentNotInMediaLib; @@ -181,7 +202,7 @@ static public function delete($ids) if (empty($ids)) { return; } - + global $wpdb; $ids = GeneralHelper::arrayToString($ids); diff --git a/src/Views/LogModal.php b/src/Views/LogModal.php index 9f16510..ef2c639 100644 --- a/src/Views/LogModal.php +++ b/src/Views/LogModal.php @@ -45,7 +45,7 @@ class="attachment-item" - +

@@ -72,11 +72,6 @@ class="attachment-item"
  • - - - -
    -
    diff --git a/testing/tests/TestLogFunctions.php b/testing/tests/TestLogFunctions.php index 001366e..442a914 100644 --- a/testing/tests/TestLogFunctions.php +++ b/testing/tests/TestLogFunctions.php @@ -385,4 +385,15 @@ public function testDoesUnevenHeaderKeysAndValuesCorrectItself() $this->assertEquals(GeneralHelper::$htmlEmailHeader, $logs[0]['additional_headers'][0]); $this->assertEquals('foo: bar', $logs[0]['additional_headers'][1]); } + + public function testCanNotReturnDbColumnsViaBlacklist() + { + wp_mail('test@test.com', 'New message', 'My message'); + + $log = Logs::get(['column_blacklist' => ['message', 'is_html', 'additional_headers']])[0]; + + $this->assertTrue(isset($log['message']) === false); + $this->assertTrue(isset($log['is_html']) === false); + $this->assertTrue(isset($log['additional_headers']) === false); + } } From e806a372be84c4a11037f3198cc0513a655fc6c6 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 4 Jun 2022 18:41:40 +0100 Subject: [PATCH 15/18] * Resolved BuddyPress error * Commented out unneeded BuddyPress logger --- src/LoggerFactory.php | 2 +- src/Loggers/BuddyPress.php | 4 ++-- src/Loggers/WpMail.php | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/LoggerFactory.php b/src/LoggerFactory.php index 880976d..bf26ba3 100644 --- a/src/LoggerFactory.php +++ b/src/LoggerFactory.php @@ -14,6 +14,6 @@ static public function Set() * that determines which one to use will go here */ new WpMail(); - new BuddyPress(); + // new BuddyPress(); } } diff --git a/src/Loggers/BuddyPress.php b/src/Loggers/BuddyPress.php index 7a21af7..f34b12e 100644 --- a/src/Loggers/BuddyPress.php +++ b/src/Loggers/BuddyPress.php @@ -20,7 +20,7 @@ public function __construct() public function recordMail($status, $bpMail) { - $this->saveMail($this->getMailArgs($bpMail)); + $this->saveMail($bpMail, $this->getTransformedMailArgs($bpMail)); } public function recordError($error) @@ -35,7 +35,7 @@ public function recordError($error) * @param BP_Email $bpMail the details of the mail going to be sent * @return array must return an array in the same format */ - protected function getMailArgs($bpMail) + protected function getTransformedMailArgs($bpMail) { $tos = array_map(function($bpRecipient) { return $bpRecipient->get_address(); diff --git a/src/Loggers/WpMail.php b/src/Loggers/WpMail.php index 76712fb..24d6189 100644 --- a/src/Loggers/WpMail.php +++ b/src/Loggers/WpMail.php @@ -3,7 +3,6 @@ namespace WpMailCatcher\Loggers; use WpMailCatcher\GeneralHelper; -use WpMailCatcher\Models\Settings; class WpMail { @@ -24,6 +23,8 @@ public function __construct() public function recordMail($args) { $this->saveMail($args, [$this, 'getTransformedMailArgs']); + + // Because this is triggered from add_filter we need to return the unmodified args return $args; } From a32d57010598be657c3b19f5b7b9753077588f2d Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 4 Jun 2022 19:25:15 +0100 Subject: [PATCH 16/18] * Fixed #139 --- src/MailAdminTable.php | 5 +++-- src/Models/Logs.php | 11 +++++++++++ src/Views/Log.php | 10 ++++++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/MailAdminTable.php b/src/MailAdminTable.php index 851f3ac..a23a584 100644 --- a/src/MailAdminTable.php +++ b/src/MailAdminTable.php @@ -155,13 +155,14 @@ function prepare_items() $this->_column_headers = [$columns, $hidden, $sortable]; $this->process_bulk_action(); - /** Can pass $_REQUEST because we whitelist and sanitize it at the model level */ + $overrideParams = array_intersect_key($_REQUEST, Logs::$whitelistedParams); + $this->items = Logs::get(array_merge([ 'paged' => $this->get_pagenum(), 'post_status' => isset($_GET['post_status']) ? $_GET['post_status'] : 'any', 'posts_per_page' => $per_page, 'column_blacklist' => ['message'] - ], $_REQUEST)); + ], $overrideParams)); $this->totalItems = Logs::getTotalAmount(); diff --git a/src/Models/Logs.php b/src/Models/Logs.php index 1d92d6e..b4ef00f 100644 --- a/src/Models/Logs.php +++ b/src/Models/Logs.php @@ -6,6 +6,17 @@ class Logs { + // Need to set null because we're using array_intersect_key + static public $whitelistedParams = [ + 'orderby' => null, + 'posts_per_page' => null, + 'paged' => null, + 'order' => null, + 'post_status' => null, + 'subject' => null, + 's' => null + ]; + static public function getTotalPages($postsPerPage = false) { if ($postsPerPage == false) { diff --git a/src/Views/Log.php b/src/Views/Log.php index 747efd0..13e7133 100644 --- a/src/Views/Log.php +++ b/src/Views/Log.php @@ -84,11 +84,17 @@ - + + + $value) : ?> + + + search_box(__('Search Logs', 'WpMailCatcher'), 'search_id'); ?> - display(); ?> + display(); ?> + From 9e600cdf4841c972d54463136955d44e8342a264 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 4 Jun 2022 21:01:19 +0100 Subject: [PATCH 17/18] * Fixed #129 --- src/Models/Settings.php | 14 ++++++++------ testing/tests/TestSettings.php | 25 +++++++++++++------------ 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/Models/Settings.php b/src/Models/Settings.php index 25ee65f..719403f 100644 --- a/src/Models/Settings.php +++ b/src/Models/Settings.php @@ -22,14 +22,16 @@ class Settings 15780000 => '6 months' ]; - static public function get($key = null) + static public function get($key = null, $bypassCache = false) { - if (self::$settings == null) { - self::$settings = unserialize(get_option(self::$optionsName, null)); - } + if (self::$settings == null || $bypassCache) { + $options = unserialize(get_option(self::$optionsName, null)); - if (self::$settings == null) { - self::installOptions(); + if (!is_array($options)) { + self::installOptions(); + } else { + self::$settings = array_merge(self::$defaultSettings, $options); + } } if ($key != null) { diff --git a/testing/tests/TestSettings.php b/testing/tests/TestSettings.php index 7a35cb5..f0a85e7 100644 --- a/testing/tests/TestSettings.php +++ b/testing/tests/TestSettings.php @@ -33,9 +33,9 @@ public function testCronEnable() $this->assertEquals($this->timescale, $cronTasks[0]['schedule']); /** - * Assert 1 instead of 0 because the new default setting for - * auto_delete is true so the next hook will start at 1 not 0 - */ + * Assert 1 instead of 0 because the new default setting for + * auto_delete is true so the next hook will start at 1 not 0 + */ $this->assertEquals(GeneralHelper::$namespacePrefix . '1', $cronTasks[0]['hook']); } @@ -49,13 +49,14 @@ public function testCronDisable() } public function testDefaultSettingsSerialization() - { - // Simulate a third party invalidating the serialized object - $invalidSerializationObj = 's:164:"a:4:{s:17:"def";}";'; - update_option(Settings::$optionsName, $invalidSerializationObj); - - // Assert that the default value is used if the value cannot be - // found within the serialized object - $this->assertEquals(true, Settings::get('auto_delete')); - } + { + // Simulate a third party invalidating the serialized object + $invalidSerializationObj = 'a:1:{s:3:"foo";s:3:"bar";}'; + update_option(Settings::$optionsName, $invalidSerializationObj); + + // Assert that the default value is used if the value cannot be + // found within the serialized object + $this->assertEquals(Settings::$defaultSettings['auto_delete'], Settings::get(null, true)['auto_delete']); + $this->assertEquals(Settings::$defaultSettings['auto_delete'], Settings::get('auto_delete', true)); + } } From 3153264472ffc9ed828bcd49a754127d8ce51e85 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sun, 12 Jun 2022 13:17:15 +0100 Subject: [PATCH 18/18] * Added test for db upgrade system * Added backwards compatibility with old log formatting --- src/Bootstrap.php | 2 +- src/DatabaseUpgradeManager.php | 92 ++++++++++----------------------- src/DatabaseUpgradeService.php | 43 +++++++++++++++ src/GeneralHelper.php | 7 +++ src/LoggerFactory.php | 2 +- src/Models/Logs.php | 14 +++-- src/Views/Log.php | 2 +- testing/tests/TestDbUpgrade.php | 31 +++++++++++ 8 files changed, 123 insertions(+), 70 deletions(-) create mode 100644 src/DatabaseUpgradeService.php create mode 100644 testing/tests/TestDbUpgrade.php diff --git a/src/Bootstrap.php b/src/Bootstrap.php index f059567..6278507 100644 --- a/src/Bootstrap.php +++ b/src/Bootstrap.php @@ -13,7 +13,7 @@ class Bootstrap public function __construct() { GeneralHelper::setSettings(); - LoggerFactory::Set(); + LoggerFactory::set(); $this->registerCronTasks(); $this->screenOptions = ScreenOptions::getInstance(); diff --git a/src/DatabaseUpgradeManager.php b/src/DatabaseUpgradeManager.php index 9492f30..330ad4f 100644 --- a/src/DatabaseUpgradeManager.php +++ b/src/DatabaseUpgradeManager.php @@ -8,75 +8,39 @@ class DatabaseUpgradeManager { static private $instance = false; - private $dbVersion; - private $upgradePaths = [ - '2.0.0' => 'doV2Upgrade', - ]; - - private function __construct() - { - $this->dbVersion = Settings::get('db_version'); - } - public static function getInstance() { - if (self::$instance == false) { - self::$instance = new DatabaseUpgradeManager(); - } - - return self::$instance; - } - - - public function isUpgradeRequired() - { - foreach ($this->upgradePaths as $version => $method) { - if ($this->dbVersion < $version) { - return true; - } - } - - return false; - } - - public function doUpgrade() - { - if (!$this->isUpgradeRequired()) { - return; + if (self::$instance == true) { + return self::$instance; } - foreach ($this->upgradePaths as $version => $method) { - if ($this->dbVersion < $version) { - $this->{$method}(); + self::$instance = new DatabaseUpgradeService([ + '2.0.0' => function () { + global $wpdb; + + // dbDelta creates a diff between the table schemas, and executes + // the necessary SQL so they match. In this case we add the column + // is_html and default it to false + $sql = "CREATE TABLE " . $wpdb->prefix . GeneralHelper::$tableName . " ( + id int NOT NULL AUTO_INCREMENT, + time int NOT NULL, + email_to text DEFAULT NULL, + subject text DEFAULT NULL, + message text DEFAULT NULL, + backtrace_segment text NOT NULL, + status bool DEFAULT 1 NOT NULL, + error text DEFAULT NULL, + attachments text DEFAULT NULL, + additional_headers text DEFAULT NULL, + is_html bool DEFAULT 0, + PRIMARY KEY (id) + ) " . $wpdb->get_charset_collate() . ";"; + + require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); + dbDelta($sql); } - } + ], Settings::get('db_version')); - Settings::update(['db_version' => GeneralHelper::$pluginVersion]); - } - - private function doV2Upgrade() - { - global $wpdb; - - // dbDelta creates a diff between the table schemas, and executes - // the necessary SQL so they match. In this case we add the column - // is_html and default it to false - $sql = "CREATE TABLE " . $wpdb->prefix . GeneralHelper::$tableName . " ( - id int NOT NULL AUTO_INCREMENT, - time int NOT NULL, - email_to text DEFAULT NULL, - subject text DEFAULT NULL, - message text DEFAULT NULL, - backtrace_segment text NOT NULL, - status bool DEFAULT 1 NOT NULL, - error text DEFAULT NULL, - attachments text DEFAULT NULL, - additional_headers text DEFAULT NULL, - is_html bool DEFAULT 0, - PRIMARY KEY (id) - ) " . $wpdb->get_charset_collate() . ";"; - - require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); - dbDelta($sql); + return self::$instance; } } diff --git a/src/DatabaseUpgradeService.php b/src/DatabaseUpgradeService.php new file mode 100644 index 0000000..90307e6 --- /dev/null +++ b/src/DatabaseUpgradeService.php @@ -0,0 +1,43 @@ +upgradePaths = $upgradePaths; + $this->dbVersion = $currentDbVersion; + } + + public function isUpgradeRequired() + { + foreach ($this->upgradePaths as $version => $function) { + if ($this->dbVersion < $version) { + return true; + } + } + + return false; + } + + public function doUpgrade() + { + if (!$this->isUpgradeRequired()) { + return; + } + + foreach ($this->upgradePaths as $version => $function) { + if ($this->dbVersion < $version) { + $function(); + } + } + + Settings::update(['db_version' => GeneralHelper::$pluginVersion]); + } +} diff --git a/src/GeneralHelper.php b/src/GeneralHelper.php index 04855ea..36eb1df 100644 --- a/src/GeneralHelper.php +++ b/src/GeneralHelper.php @@ -241,6 +241,13 @@ static public function getPrefixedSlug($slugOrLabel) { return self::$namespacePrefix . self::labelToSlug($slugOrLabel); } + + static public function dd($value) + { + echo '
    ';
    +        print_r($value);
    +        exit;
    +    }
     }
     
     
    diff --git a/src/LoggerFactory.php b/src/LoggerFactory.php
    index bf26ba3..05fae69 100644
    --- a/src/LoggerFactory.php
    +++ b/src/LoggerFactory.php
    @@ -7,7 +7,7 @@
     
     class LoggerFactory
     {
    -    static public function Set()
    +    static public function set()
         {
             /**
              *  When more loggers are added, the logic
    diff --git a/src/Models/Logs.php b/src/Models/Logs.php
    index b4ef00f..9c6a494 100644
    --- a/src/Models/Logs.php
    +++ b/src/Models/Logs.php
    @@ -70,10 +70,14 @@ static public function get($args = [])
     
             $defaultColumns = [
                 'id', 'time', 'email_to', 'subject', 'message',
    -            'status', 'error', 'backtrace_segment', 'attachments', 'is_html',
    +            'status', 'error', 'backtrace_segment', 'attachments',
                 'additional_headers'
             ];
     
    +        if (Settings::get('db_version') >= '2.0.0') {
    +            $defaultColumns[] = 'is_html';
    +        }
    +
             $columnsToSelect = array_diff($defaultColumns, $args['column_blacklist']);
     
             /**
    @@ -168,8 +172,12 @@ static private function dbResultTransform($results, $args = [])
                     $result['time'] = $args['date_time_format'] == 'human' ? GeneralHelper::getHumanReadableTimeFromNow($result['timestamp']) : date($args['date_time_format'], $result['timestamp']);
                 }
     
    -            if (isset($result['is_html']) && isset($result['additional_headers'])) {
    -                $result['is_html'] = $result['is_html'] ? (bool)$result['is_html'] : GeneralHelper::doesArrayContainSubString($result['additional_headers'], GeneralHelper::$htmlEmailHeader);
    +            // This will exist if the db_version is >= 2.0.0
    +            if (isset($result['is_html']) && $result['is_html'] == true) {
    +                $result['is_html'] = (bool)$result['is_html'];
    +            // Otherwise resort to the original method
    +            } else if (isset($result['additional_headers'])) {
    +                $result['is_html'] = GeneralHelper::doesArrayContainSubString($result['additional_headers'], GeneralHelper::$htmlEmailHeader);
                 }
     
                 if (isset($result['message'])) {
    diff --git a/src/Views/Log.php b/src/Views/Log.php
    index 13e7133..d1184e9 100644
    --- a/src/Views/Log.php
    +++ b/src/Views/Log.php
    @@ -23,7 +23,7 @@
                 

    here to upgrade your database', + printf(__('Your WP Mail Catcher database needs upgrading. Click here to perform the upgrade.', 'WpMailCatcher'), '?page=' . GeneralHelper::$adminPageSlug . '&action=upgrade-database' ); diff --git a/testing/tests/TestDbUpgrade.php b/testing/tests/TestDbUpgrade.php new file mode 100644 index 0000000..403752a --- /dev/null +++ b/testing/tests/TestDbUpgrade.php @@ -0,0 +1,31 @@ + function () use (&$wasV05UpgradeCalled) { + $wasV05UpgradeCalled = true; + }, + '2.0.0' => function () use (&$wasV2UpgradeCalled) { + $wasV2UpgradeCalled = true; + }, + '2.5.0' => function () use (&$wasV25UpgradeCalled) { + $wasV25UpgradeCalled = true; + }, + ], '1.0.0'); + + $dbUpgradeManager->doUpgrade(); + + $this->assertFalse($wasV05UpgradeCalled); + $this->assertTrue($wasV2UpgradeCalled); + $this->assertTrue($wasV25UpgradeCalled); + } +}