From 4d37ae30ae7c77145cb810c80b145d9642f3d70c Mon Sep 17 00:00:00 2001 From: "J. King" Date: Sun, 5 Jun 2022 21:38:08 -0400 Subject: [PATCH 01/16] Update dependencies Addresses a Guzzle vulnerability, though it does not affect The Arsse --- composer.lock | 98 +++++++--- vendor-bin/csfixer/composer.lock | 227 +++++++++++------------ vendor-bin/daux/composer.lock | 239 ++++++++++++------------ vendor-bin/phpstan/composer.lock | 2 +- vendor-bin/phpunit/composer.lock | 178 +++--------------- vendor-bin/robo/composer.lock | 301 +++++++++++++++++++------------ 6 files changed, 517 insertions(+), 528 deletions(-) diff --git a/composer.lock b/composer.lock index 57bae4a3..816aff14 100644 --- a/composer.lock +++ b/composer.lock @@ -58,16 +58,16 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.5.5", + "version": "6.5.6", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e" + "reference": "f092dd734083473658de3ee4bef093ed77d2689c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", - "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f092dd734083473658de3ee4bef093ed77d2689c", + "reference": "f092dd734083473658de3ee4bef093ed77d2689c", "shasum": "" }, "require": { @@ -104,10 +104,40 @@ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], "description": "Guzzle is a PHP HTTP client library", @@ -123,9 +153,23 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/6.5" + "source": "https://github.com/guzzle/guzzle/tree/6.5.6" }, - "time": "2020-06-16T21:01:06+00:00" + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2022-05-25T13:19:12+00:00" }, { "name": "guzzlehttp/promises", @@ -1109,16 +1153,16 @@ }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "749045c69efb97c70d25d7463abba812e91f3a44" + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/749045c69efb97c70d25d7463abba812e91f3a44", - "reference": "749045c69efb97c70d25d7463abba812e91f3a44", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8", + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8", "shasum": "" }, "require": { @@ -1132,7 +1176,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1176,7 +1220,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.26.0" }, "funding": [ { @@ -1192,20 +1236,20 @@ "type": "tidelift" } ], - "time": "2021-09-14T14:02:44+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "219aa369ceff116e673852dce47c3a41794c14bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd", "shasum": "" }, "require": { @@ -1217,7 +1261,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1260,7 +1304,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" }, "funding": [ { @@ -1276,20 +1320,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" + "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/bf44a9fd41feaac72b074de600314a93e2ae78e2", + "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2", "shasum": "" }, "require": { @@ -1298,7 +1342,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1336,7 +1380,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.26.0" }, "funding": [ { @@ -1352,7 +1396,7 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:17:38+00:00" + "time": "2022-05-24T11:49:31+00:00" } ], "packages-dev": [ diff --git a/vendor-bin/csfixer/composer.lock b/vendor-bin/csfixer/composer.lock index 4c89ef5b..1f322d06 100644 --- a/vendor-bin/csfixer/composer.lock +++ b/vendor-bin/csfixer/composer.lock @@ -741,16 +741,16 @@ }, { "name": "symfony/console", - "version": "v5.4.7", + "version": "v5.4.9", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "900275254f0a1a2afff1ab0e11abd5587a10e1d6" + "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/900275254f0a1a2afff1ab0e11abd5587a10e1d6", - "reference": "900275254f0a1a2afff1ab0e11abd5587a10e1d6", + "url": "https://api.github.com/repos/symfony/console/zipball/829d5d1bf60b2efeb0887b7436873becc71a45eb", + "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb", "shasum": "" }, "require": { @@ -820,7 +820,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.7" + "source": "https://github.com/symfony/console/tree/v5.4.9" }, "funding": [ { @@ -836,29 +836,29 @@ "type": "tidelift" } ], - "time": "2022-03-31T17:09:19+00:00" + "time": "2022-05-18T06:17:34+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.0.0", + "version": "v3.1.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced" + "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/c726b64c1ccfe2896cb7df2e1331c357ad1c8ced", - "reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", + "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", @@ -887,7 +887,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.0" }, "funding": [ { @@ -903,20 +903,20 @@ "type": "tidelift" } ], - "time": "2021-11-01T23:48:49+00:00" + "time": "2022-02-25T11:15:52+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v5.4.3", + "version": "v5.4.9", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "dec8a9f58d20df252b9cd89f1c6c1530f747685d" + "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/dec8a9f58d20df252b9cd89f1c6c1530f747685d", - "reference": "dec8a9f58d20df252b9cd89f1c6c1530f747685d", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", + "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", "shasum": "" }, "require": { @@ -972,7 +972,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.3" + "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.9" }, "funding": [ { @@ -988,24 +988,24 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-05-05T16:45:39+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.0.0", + "version": "v3.1.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "aa5422287b75594b90ee9cd807caf8f0df491385" + "reference": "02ff5eea2f453731cfbc6bc215e456b781480448" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/aa5422287b75594b90ee9cd807caf8f0df491385", - "reference": "aa5422287b75594b90ee9cd807caf8f0df491385", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/02ff5eea2f453731cfbc6bc215e456b781480448", + "reference": "02ff5eea2f453731cfbc6bc215e456b781480448", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "psr/event-dispatcher": "^1" }, "suggest": { @@ -1014,7 +1014,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", @@ -1051,7 +1051,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.0.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.1.0" }, "funding": [ { @@ -1067,20 +1067,20 @@ "type": "tidelift" } ], - "time": "2021-07-15T12:33:35+00:00" + "time": "2022-02-25T11:15:52+00:00" }, { "name": "symfony/filesystem", - "version": "v5.4.7", + "version": "v5.4.9", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "3a4442138d80c9f7b600fb297534ac718b61d37f" + "reference": "36a017fa4cce1eff1b8e8129ff53513abcef05ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/3a4442138d80c9f7b600fb297534ac718b61d37f", - "reference": "3a4442138d80c9f7b600fb297534ac718b61d37f", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/36a017fa4cce1eff1b8e8129ff53513abcef05ba", + "reference": "36a017fa4cce1eff1b8e8129ff53513abcef05ba", "shasum": "" }, "require": { @@ -1115,7 +1115,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.7" + "source": "https://github.com/symfony/filesystem/tree/v5.4.9" }, "funding": [ { @@ -1131,20 +1131,20 @@ "type": "tidelift" } ], - "time": "2022-04-01T12:33:59+00:00" + "time": "2022-05-20T13:55:35+00:00" }, { "name": "symfony/finder", - "version": "v5.4.3", + "version": "v5.4.8", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d" + "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/231313534dded84c7ecaa79d14bc5da4ccb69b7d", - "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d", + "url": "https://api.github.com/repos/symfony/finder/zipball/9b630f3427f3ebe7cd346c277a1408b00249dad9", + "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9", "shasum": "" }, "require": { @@ -1178,7 +1178,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.3" + "source": "https://github.com/symfony/finder/tree/v5.4.8" }, "funding": [ { @@ -1194,7 +1194,7 @@ "type": "tidelift" } ], - "time": "2022-01-26T16:34:36+00:00" + "time": "2022-04-15T08:07:45+00:00" }, { "name": "symfony/options-resolver", @@ -1267,16 +1267,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "30885182c981ab175d4d034db0f6f469898070ab" + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", - "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", "shasum": "" }, "require": { @@ -1291,7 +1291,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1329,7 +1329,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0" }, "funding": [ { @@ -1345,20 +1345,20 @@ "type": "tidelift" } ], - "time": "2021-10-20T20:35:02+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" + "reference": "433d05519ce6990bf3530fba6957499d327395c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2", + "reference": "433d05519ce6990bf3530fba6957499d327395c2", "shasum": "" }, "require": { @@ -1370,7 +1370,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1410,7 +1410,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0" }, "funding": [ { @@ -1426,20 +1426,20 @@ "type": "tidelift" } ], - "time": "2021-11-23T21:10:46+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "219aa369ceff116e673852dce47c3a41794c14bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd", "shasum": "" }, "require": { @@ -1451,7 +1451,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1494,7 +1494,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" }, "funding": [ { @@ -1510,20 +1510,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", "shasum": "" }, "require": { @@ -1538,7 +1538,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1577,7 +1577,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" }, "funding": [ { @@ -1593,7 +1593,7 @@ "type": "tidelift" } ], - "time": "2021-11-30T18:21:41+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php70", @@ -1665,16 +1665,16 @@ }, { "name": "symfony/polyfill-php72", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" + "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/bf44a9fd41feaac72b074de600314a93e2ae78e2", + "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2", "shasum": "" }, "require": { @@ -1683,7 +1683,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1721,7 +1721,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.26.0" }, "funding": [ { @@ -1737,20 +1737,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:17:38+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85", + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85", "shasum": "" }, "require": { @@ -1759,7 +1759,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1800,7 +1800,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0" }, "funding": [ { @@ -1816,20 +1816,20 @@ "type": "tidelift" } ], - "time": "2021-06-05T21:20:04+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c" + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", "shasum": "" }, "require": { @@ -1838,7 +1838,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1883,7 +1883,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" }, "funding": [ { @@ -1899,20 +1899,20 @@ "type": "tidelift" } ], - "time": "2022-03-04T08:16:47+00:00" + "time": "2022-05-10T07:21:04+00:00" }, { "name": "symfony/process", - "version": "v5.4.7", + "version": "v5.4.8", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "38a44b2517b470a436e1c944bf9b9ba3961137fb" + "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/38a44b2517b470a436e1c944bf9b9ba3961137fb", - "reference": "38a44b2517b470a436e1c944bf9b9ba3961137fb", + "url": "https://api.github.com/repos/symfony/process/zipball/597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", + "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", "shasum": "" }, "require": { @@ -1945,7 +1945,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.7" + "source": "https://github.com/symfony/process/tree/v5.4.8" }, "funding": [ { @@ -1961,24 +1961,24 @@ "type": "tidelift" } ], - "time": "2022-03-18T16:18:52+00:00" + "time": "2022-04-08T05:07:18+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.0.0", + "version": "v3.1.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "36715ebf9fb9db73db0cb24263c79077c6fe8603" + "reference": "d66cd8ab656780f62c4215b903a420eb86358957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/36715ebf9fb9db73db0cb24263c79077c6fe8603", - "reference": "36715ebf9fb9db73db0cb24263c79077c6fe8603", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d66cd8ab656780f62c4215b903a420eb86358957", + "reference": "d66cd8ab656780f62c4215b903a420eb86358957", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "psr/container": "^2.0" }, "conflict": { @@ -1990,7 +1990,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", @@ -2000,7 +2000,10 @@ "autoload": { "psr-4": { "Symfony\\Contracts\\Service\\": "" - } + }, + "exclude-from-classmap": [ + "/Test/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2027,7 +2030,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.0.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.1.0" }, "funding": [ { @@ -2043,7 +2046,7 @@ "type": "tidelift" } ], - "time": "2021-11-04T17:53:12+00:00" + "time": "2022-05-07T08:07:09+00:00" }, { "name": "symfony/stopwatch", @@ -2109,20 +2112,20 @@ }, { "name": "symfony/string", - "version": "v6.0.3", + "version": "v6.1.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "522144f0c4c004c80d56fa47e40e17028e2eefc2" + "reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/522144f0c4c004c80d56fa47e40e17028e2eefc2", - "reference": "522144f0c4c004c80d56fa47e40e17028e2eefc2", + "url": "https://api.github.com/repos/symfony/string/zipball/d3edc75baf9f1d4f94879764dda2e1ac33499529", + "reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", @@ -2174,7 +2177,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.0.3" + "source": "https://github.com/symfony/string/tree/v6.1.0" }, "funding": [ { @@ -2190,7 +2193,7 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:55:41+00:00" + "time": "2022-04-22T08:18:23+00:00" } ], "aliases": [], @@ -2200,5 +2203,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.3.0" } diff --git a/vendor-bin/daux/composer.lock b/vendor-bin/daux/composer.lock index b7d0ac28..c5724031 100644 --- a/vendor-bin/daux/composer.lock +++ b/vendor-bin/daux/composer.lock @@ -83,16 +83,16 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.4.2", + "version": "7.4.3", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "ac1ec1cd9b5624694c3a40be801d94137afb12b4" + "reference": "74a8602c6faec9ef74b7a9391ac82c5e65b1cdab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/ac1ec1cd9b5624694c3a40be801d94137afb12b4", - "reference": "ac1ec1cd9b5624694c3a40be801d94137afb12b4", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/74a8602c6faec9ef74b7a9391ac82c5e65b1cdab", + "reference": "74a8602c6faec9ef74b7a9391ac82c5e65b1cdab", "shasum": "" }, "require": { @@ -187,7 +187,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.4.2" + "source": "https://github.com/guzzle/guzzle/tree/7.4.3" }, "funding": [ { @@ -203,7 +203,7 @@ "type": "tidelift" } ], - "time": "2022-03-20T14:16:28+00:00" + "time": "2022-05-25T13:24:33+00:00" }, { "name": "guzzlehttp/promises", @@ -898,16 +898,16 @@ }, { "name": "symfony/console", - "version": "v5.4.7", + "version": "v5.4.9", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "900275254f0a1a2afff1ab0e11abd5587a10e1d6" + "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/900275254f0a1a2afff1ab0e11abd5587a10e1d6", - "reference": "900275254f0a1a2afff1ab0e11abd5587a10e1d6", + "url": "https://api.github.com/repos/symfony/console/zipball/829d5d1bf60b2efeb0887b7436873becc71a45eb", + "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb", "shasum": "" }, "require": { @@ -977,7 +977,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.7" + "source": "https://github.com/symfony/console/tree/v5.4.9" }, "funding": [ { @@ -993,29 +993,29 @@ "type": "tidelift" } ], - "time": "2022-03-31T17:09:19+00:00" + "time": "2022-05-18T06:17:34+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.0.0", + "version": "v3.1.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced" + "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/c726b64c1ccfe2896cb7df2e1331c357ad1c8ced", - "reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", + "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", @@ -1044,7 +1044,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.0" }, "funding": [ { @@ -1060,20 +1060,20 @@ "type": "tidelift" } ], - "time": "2021-11-01T23:48:49+00:00" + "time": "2022-02-25T11:15:52+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.4.6", + "version": "v5.4.9", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "34e89bc147633c0f9dd6caaaf56da3b806a21465" + "reference": "6b0d0e4aca38d57605dcd11e2416994b38774522" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/34e89bc147633c0f9dd6caaaf56da3b806a21465", - "reference": "34e89bc147633c0f9dd6caaaf56da3b806a21465", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6b0d0e4aca38d57605dcd11e2416994b38774522", + "reference": "6b0d0e4aca38d57605dcd11e2416994b38774522", "shasum": "" }, "require": { @@ -1117,7 +1117,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.6" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.9" }, "funding": [ { @@ -1133,20 +1133,20 @@ "type": "tidelift" } ], - "time": "2022-03-05T21:03:43+00:00" + "time": "2022-05-17T15:07:29+00:00" }, { "name": "symfony/mime", - "version": "v5.4.7", + "version": "v5.4.9", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "92d27a34dea2e199fa9b687e3fff3a7d169b7b1c" + "reference": "2b3802a24e48d0cfccf885173d2aac91e73df92e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/92d27a34dea2e199fa9b687e3fff3a7d169b7b1c", - "reference": "92d27a34dea2e199fa9b687e3fff3a7d169b7b1c", + "url": "https://api.github.com/repos/symfony/mime/zipball/2b3802a24e48d0cfccf885173d2aac91e73df92e", + "reference": "2b3802a24e48d0cfccf885173d2aac91e73df92e", "shasum": "" }, "require": { @@ -1200,7 +1200,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.4.7" + "source": "https://github.com/symfony/mime/tree/v5.4.9" }, "funding": [ { @@ -1216,20 +1216,20 @@ "type": "tidelift" } ], - "time": "2022-03-11T16:08:05+00:00" + "time": "2022-05-21T10:24:18+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "30885182c981ab175d4d034db0f6f469898070ab" + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", - "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", "shasum": "" }, "require": { @@ -1244,7 +1244,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1282,7 +1282,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0" }, "funding": [ { @@ -1298,20 +1298,20 @@ "type": "tidelift" } ], - "time": "2021-10-20T20:35:02+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" + "reference": "433d05519ce6990bf3530fba6957499d327395c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2", + "reference": "433d05519ce6990bf3530fba6957499d327395c2", "shasum": "" }, "require": { @@ -1323,7 +1323,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1363,7 +1363,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0" }, "funding": [ { @@ -1379,20 +1379,20 @@ "type": "tidelift" } ], - "time": "2021-11-23T21:10:46+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-icu", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-icu.git", - "reference": "c023a439b8551e320cc3c8433b198e408a623af1" + "reference": "e407643d610e5f2c8a4b14189150f68934bf5e48" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/c023a439b8551e320cc3c8433b198e408a623af1", - "reference": "c023a439b8551e320cc3c8433b198e408a623af1", + "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/e407643d610e5f2c8a4b14189150f68934bf5e48", + "reference": "e407643d610e5f2c8a4b14189150f68934bf5e48", "shasum": "" }, "require": { @@ -1404,7 +1404,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1450,7 +1450,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.26.0" }, "funding": [ { @@ -1466,20 +1466,20 @@ "type": "tidelift" } ], - "time": "2021-10-26T17:16:04+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "749045c69efb97c70d25d7463abba812e91f3a44" + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/749045c69efb97c70d25d7463abba812e91f3a44", - "reference": "749045c69efb97c70d25d7463abba812e91f3a44", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8", + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8", "shasum": "" }, "require": { @@ -1493,7 +1493,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1537,7 +1537,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.26.0" }, "funding": [ { @@ -1553,20 +1553,20 @@ "type": "tidelift" } ], - "time": "2021-09-14T14:02:44+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "219aa369ceff116e673852dce47c3a41794c14bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd", "shasum": "" }, "require": { @@ -1578,7 +1578,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1621,7 +1621,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" }, "funding": [ { @@ -1637,20 +1637,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", "shasum": "" }, "require": { @@ -1665,7 +1665,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1704,7 +1704,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" }, "funding": [ { @@ -1720,20 +1720,20 @@ "type": "tidelift" } ], - "time": "2021-11-30T18:21:41+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" + "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/bf44a9fd41feaac72b074de600314a93e2ae78e2", + "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2", "shasum": "" }, "require": { @@ -1742,7 +1742,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1780,7 +1780,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.26.0" }, "funding": [ { @@ -1796,20 +1796,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:17:38+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85", + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85", "shasum": "" }, "require": { @@ -1818,7 +1818,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1859,7 +1859,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0" }, "funding": [ { @@ -1875,20 +1875,20 @@ "type": "tidelift" } ], - "time": "2021-06-05T21:20:04+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c" + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", "shasum": "" }, "require": { @@ -1897,7 +1897,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1942,7 +1942,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" }, "funding": [ { @@ -1958,20 +1958,20 @@ "type": "tidelift" } ], - "time": "2022-03-04T08:16:47+00:00" + "time": "2022-05-10T07:21:04+00:00" }, { "name": "symfony/process", - "version": "v5.4.7", + "version": "v5.4.8", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "38a44b2517b470a436e1c944bf9b9ba3961137fb" + "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/38a44b2517b470a436e1c944bf9b9ba3961137fb", - "reference": "38a44b2517b470a436e1c944bf9b9ba3961137fb", + "url": "https://api.github.com/repos/symfony/process/zipball/597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", + "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", "shasum": "" }, "require": { @@ -2004,7 +2004,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.7" + "source": "https://github.com/symfony/process/tree/v5.4.8" }, "funding": [ { @@ -2020,24 +2020,24 @@ "type": "tidelift" } ], - "time": "2022-03-18T16:18:52+00:00" + "time": "2022-04-08T05:07:18+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.0.0", + "version": "v3.1.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "36715ebf9fb9db73db0cb24263c79077c6fe8603" + "reference": "d66cd8ab656780f62c4215b903a420eb86358957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/36715ebf9fb9db73db0cb24263c79077c6fe8603", - "reference": "36715ebf9fb9db73db0cb24263c79077c6fe8603", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d66cd8ab656780f62c4215b903a420eb86358957", + "reference": "d66cd8ab656780f62c4215b903a420eb86358957", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "psr/container": "^2.0" }, "conflict": { @@ -2049,7 +2049,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", @@ -2059,7 +2059,10 @@ "autoload": { "psr-4": { "Symfony\\Contracts\\Service\\": "" - } + }, + "exclude-from-classmap": [ + "/Test/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2086,7 +2089,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.0.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.1.0" }, "funding": [ { @@ -2102,24 +2105,24 @@ "type": "tidelift" } ], - "time": "2021-11-04T17:53:12+00:00" + "time": "2022-05-07T08:07:09+00:00" }, { "name": "symfony/string", - "version": "v6.0.3", + "version": "v6.1.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "522144f0c4c004c80d56fa47e40e17028e2eefc2" + "reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/522144f0c4c004c80d56fa47e40e17028e2eefc2", - "reference": "522144f0c4c004c80d56fa47e40e17028e2eefc2", + "url": "https://api.github.com/repos/symfony/string/zipball/d3edc75baf9f1d4f94879764dda2e1ac33499529", + "reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", @@ -2171,7 +2174,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.0.3" + "source": "https://github.com/symfony/string/tree/v6.1.0" }, "funding": [ { @@ -2187,7 +2190,7 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:55:41+00:00" + "time": "2022-04-22T08:18:23+00:00" }, { "name": "symfony/yaml", @@ -2344,5 +2347,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.3.0" } diff --git a/vendor-bin/phpstan/composer.lock b/vendor-bin/phpstan/composer.lock index c735af88..defcc9ba 100644 --- a/vendor-bin/phpstan/composer.lock +++ b/vendor-bin/phpstan/composer.lock @@ -79,5 +79,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.3.0" } diff --git a/vendor-bin/phpunit/composer.lock b/vendor-bin/phpunit/composer.lock index 4fa10765..6dc54298 100644 --- a/vendor-bin/phpunit/composer.lock +++ b/vendor-bin/phpunit/composer.lock @@ -448,16 +448,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.13.2", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077" + "reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/34bea19b6e03d8153165d8f30bba4c3be86184c1", + "reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1", "shasum": "" }, "require": { @@ -498,9 +498,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.14.0" }, - "time": "2021-11-30T19:35:32+00:00" + "time": "2022-05-31T20:59:12+00:00" }, { "name": "phar-io/manifest", @@ -2225,88 +2225,6 @@ ], "time": "2020-09-28T06:39:44+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", @@ -2359,21 +2277,21 @@ }, { "name": "webmozart/assert", - "version": "1.10.0", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "symfony/polyfill-ctype": "^1.8" + "ext-ctype": "*", + "php": "^7.2 || ^8.0" }, "conflict": { "phpstan/phpstan": "<0.12.20", @@ -2411,27 +2329,26 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.10.0" + "source": "https://github.com/webmozarts/assert/tree/1.11.0" }, - "time": "2021-03-09T10:59:23+00:00" + "time": "2022-06-03T18:03:27+00:00" }, { "name": "webmozart/glob", - "version": "4.4.0", + "version": "4.6.0", "source": { "type": "git", "url": "https://github.com/webmozarts/glob.git", - "reference": "539b5dbc10021d3f9242e7a9e9b6b37843179e83" + "reference": "3c17f7dec3d9d0e87b575026011f2e75a56ed655" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/glob/zipball/539b5dbc10021d3f9242e7a9e9b6b37843179e83", - "reference": "539b5dbc10021d3f9242e7a9e9b6b37843179e83", + "url": "https://api.github.com/repos/webmozarts/glob/zipball/3c17f7dec3d9d0e87b575026011f2e75a56ed655", + "reference": "3c17f7dec3d9d0e87b575026011f2e75a56ed655", "shasum": "" }, "require": { - "php": "^7.3 || ^8.0.0", - "webmozart/path-util": "^2.2" + "php": "^7.3 || ^8.0.0" }, "require-dev": { "phpunit/phpunit": "^9.5", @@ -2461,60 +2378,9 @@ "description": "A PHP implementation of Ant's glob.", "support": { "issues": "https://github.com/webmozarts/glob/issues", - "source": "https://github.com/webmozarts/glob/tree/4.4.0" + "source": "https://github.com/webmozarts/glob/tree/4.6.0" }, - "time": "2021-10-07T16:13:08+00:00" - }, - { - "name": "webmozart/path-util", - "version": "2.3.0", - "source": { - "type": "git", - "url": "https://github.com/webmozart/path-util.git", - "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725", - "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "webmozart/assert": "~1.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\PathUtil\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.", - "support": { - "issues": "https://github.com/webmozart/path-util/issues", - "source": "https://github.com/webmozart/path-util/tree/2.3.0" - }, - "abandoned": "symfony/filesystem", - "time": "2015-12-17T08:42:14+00:00" + "time": "2022-05-24T19:45:58+00:00" } ], "aliases": [], @@ -2524,5 +2390,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.3.0" } diff --git a/vendor-bin/robo/composer.lock b/vendor-bin/robo/composer.lock index 1849110a..21825423 100644 --- a/vendor-bin/robo/composer.lock +++ b/vendor-bin/robo/composer.lock @@ -90,22 +90,22 @@ }, { "name": "consolidation/annotated-command", - "version": "4.5.3", + "version": "4.5.5", "source": { "type": "git", "url": "https://github.com/consolidation/annotated-command.git", - "reference": "1941a743e63993288e09d0686a4cb7ed47813213" + "reference": "67cea8e8e7656b74da651ea6f49321853996c0fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/1941a743e63993288e09d0686a4cb7ed47813213", - "reference": "1941a743e63993288e09d0686a4cb7ed47813213", + "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/67cea8e8e7656b74da651ea6f49321853996c0fd", + "reference": "67cea8e8e7656b74da651ea6f49321853996c0fd", "shasum": "" }, "require": { "consolidation/output-formatters": "^4.1.1", "php": ">=7.1.3", - "psr/log": "^1|^2", + "psr/log": "^1|^2|^3", "symfony/console": "^4.4.8|^5|^6", "symfony/event-dispatcher": "^4.4.8|^5|^6", "symfony/finder": "^4.4.8|^5|^6" @@ -119,7 +119,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "5.x-dev" + "dev-main": "4.x-dev" } }, "autoload": { @@ -140,9 +140,9 @@ "description": "Initialize Symfony Console commands from annotated command class methods.", "support": { "issues": "https://github.com/consolidation/annotated-command/issues", - "source": "https://github.com/consolidation/annotated-command/tree/4.5.3" + "source": "https://github.com/consolidation/annotated-command/tree/4.5.5" }, - "time": "2022-04-02T00:17:53+00:00" + "time": "2022-04-26T16:18:25+00:00" }, { "name": "consolidation/config", @@ -546,26 +546,25 @@ }, { "name": "grasmash/expander", - "version": "2.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/grasmash/expander.git", - "reference": "f4df21d01d1fbda38269cca89e3dbb6ba223da7f" + "reference": "b7cbc1f2fdf9a9c0e253a424c2a4058316b7cb6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/grasmash/expander/zipball/f4df21d01d1fbda38269cca89e3dbb6ba223da7f", - "reference": "f4df21d01d1fbda38269cca89e3dbb6ba223da7f", + "url": "https://api.github.com/repos/grasmash/expander/zipball/b7cbc1f2fdf9a9c0e253a424c2a4058316b7cb6e", + "reference": "b7cbc1f2fdf9a9c0e253a424c2a4058316b7cb6e", "shasum": "" }, "require": { "dflydev/dot-access-data": "^3.0.0", - "php": ">=5.6", - "psr/log": "^1 | ^2" + "php": ">=7.1", + "psr/log": "^1 | ^2 | ^3" }, "require-dev": { "greg-1-anderson/composer-test-scenarios": "^1", - "php-coveralls/php-coveralls": "^2.0", "phpunit/phpunit": "^6.0 || ^8.0 || ^9", "squizlabs/php_codesniffer": "^2.7 || ^3.3" }, @@ -592,9 +591,9 @@ "description": "Expands internal property references in PHP arrays file.", "support": { "issues": "https://github.com/grasmash/expander/issues", - "source": "https://github.com/grasmash/expander/tree/2.0.2" + "source": "https://github.com/grasmash/expander/tree/2.0.3" }, - "time": "2022-02-24T03:58:20+00:00" + "time": "2022-04-25T22:17:46+00:00" }, { "name": "league/container", @@ -1071,20 +1070,21 @@ }, { "name": "symfony/console", - "version": "v6.0.7", + "version": "v6.1.0", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "70dcf7b2ca2ea08ad6ebcc475f104a024fb5632e" + "reference": "c9646197ef43b0e2ff44af61e7f0571526fd4170" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/70dcf7b2ca2ea08ad6ebcc475f104a024fb5632e", - "reference": "70dcf7b2ca2ea08ad6ebcc475f104a024fb5632e", + "url": "https://api.github.com/repos/symfony/console/zipball/c9646197ef43b0e2ff44af61e7f0571526fd4170", + "reference": "c9646197ef43b0e2ff44af61e7f0571526fd4170", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^1.1|^2|^3", "symfony/string": "^5.4|^6.0" @@ -1146,7 +1146,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.0.7" + "source": "https://github.com/symfony/console/tree/v6.1.0" }, "funding": [ { @@ -1162,24 +1162,91 @@ "type": "tidelift" } ], - "time": "2022-03-31T17:18:25+00:00" + "time": "2022-05-27T06:34:22+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v6.0.3", + "name": "symfony/deprecation-contracts", + "version": "v3.1.0", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "6472ea2dd415e925b90ca82be64b8bc6157f3934" + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/6472ea2dd415e925b90ca82be64b8bc6157f3934", - "reference": "6472ea2dd415e925b90ca82be64b8bc6157f3934", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", + "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.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": "2022-02-25T11:15:52+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v6.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "a0449a7ad7daa0f7c0acd508259f80544ab5a347" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a0449a7ad7daa0f7c0acd508259f80544ab5a347", + "reference": "a0449a7ad7daa0f7c0acd508259f80544ab5a347", + "shasum": "" + }, + "require": { + "php": ">=8.1", "symfony/event-dispatcher-contracts": "^2|^3" }, "conflict": { @@ -1229,7 +1296,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.0.3" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.1.0" }, "funding": [ { @@ -1245,24 +1312,24 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:55:41+00:00" + "time": "2022-05-05T16:51:07+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.0.0", + "version": "v3.1.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "aa5422287b75594b90ee9cd807caf8f0df491385" + "reference": "02ff5eea2f453731cfbc6bc215e456b781480448" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/aa5422287b75594b90ee9cd807caf8f0df491385", - "reference": "aa5422287b75594b90ee9cd807caf8f0df491385", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/02ff5eea2f453731cfbc6bc215e456b781480448", + "reference": "02ff5eea2f453731cfbc6bc215e456b781480448", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "psr/event-dispatcher": "^1" }, "suggest": { @@ -1271,7 +1338,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", @@ -1308,7 +1375,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.0.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.1.0" }, "funding": [ { @@ -1324,24 +1391,24 @@ "type": "tidelift" } ], - "time": "2021-07-15T12:33:35+00:00" + "time": "2022-02-25T11:15:52+00:00" }, { "name": "symfony/filesystem", - "version": "v6.0.7", + "version": "v6.1.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "6c9e4c41f2c51dfde3db298594ed9cba55dbf5ff" + "reference": "3132d2f43ca799c2aa099f9738d98228c56baa5d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/6c9e4c41f2c51dfde3db298594ed9cba55dbf5ff", - "reference": "6c9e4c41f2c51dfde3db298594ed9cba55dbf5ff", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/3132d2f43ca799c2aa099f9738d98228c56baa5d", + "reference": "3132d2f43ca799c2aa099f9738d98228c56baa5d", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, @@ -1371,7 +1438,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.0.7" + "source": "https://github.com/symfony/filesystem/tree/v6.1.0" }, "funding": [ { @@ -1387,24 +1454,27 @@ "type": "tidelift" } ], - "time": "2022-04-01T12:54:51+00:00" + "time": "2022-05-21T13:34:40+00:00" }, { "name": "symfony/finder", - "version": "v6.0.3", + "version": "v6.1.0", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "8661b74dbabc23223f38c9b99d3f8ade71170430" + "reference": "45b8beb69d6eb3b05a65689ebfd4222326773f8f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/8661b74dbabc23223f38c9b99d3f8ade71170430", - "reference": "8661b74dbabc23223f38c9b99d3f8ade71170430", + "url": "https://api.github.com/repos/symfony/finder/zipball/45b8beb69d6eb3b05a65689ebfd4222326773f8f", + "reference": "45b8beb69d6eb3b05a65689ebfd4222326773f8f", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=8.1" + }, + "require-dev": { + "symfony/filesystem": "^6.0" }, "type": "library", "autoload": { @@ -1432,7 +1502,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.0.3" + "source": "https://github.com/symfony/finder/tree/v6.1.0" }, "funding": [ { @@ -1448,20 +1518,20 @@ "type": "tidelift" } ], - "time": "2022-01-26T17:23:29+00:00" + "time": "2022-04-15T08:08:08+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "30885182c981ab175d4d034db0f6f469898070ab" + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", - "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", "shasum": "" }, "require": { @@ -1476,7 +1546,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1514,7 +1584,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0" }, "funding": [ { @@ -1530,20 +1600,20 @@ "type": "tidelift" } ], - "time": "2021-10-20T20:35:02+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" + "reference": "433d05519ce6990bf3530fba6957499d327395c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2", + "reference": "433d05519ce6990bf3530fba6957499d327395c2", "shasum": "" }, "require": { @@ -1555,7 +1625,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1595,7 +1665,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0" }, "funding": [ { @@ -1611,20 +1681,20 @@ "type": "tidelift" } ], - "time": "2021-11-23T21:10:46+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "219aa369ceff116e673852dce47c3a41794c14bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd", "shasum": "" }, "require": { @@ -1636,7 +1706,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1679,7 +1749,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" }, "funding": [ { @@ -1695,20 +1765,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", "shasum": "" }, "require": { @@ -1723,7 +1793,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1762,7 +1832,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" }, "funding": [ { @@ -1778,24 +1848,24 @@ "type": "tidelift" } ], - "time": "2021-11-30T18:21:41+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/process", - "version": "v6.0.7", + "version": "v6.1.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "e13f6757e267d687e20ec5b26ccfcbbe511cd8f4" + "reference": "318718453c2be58266f1a9e74063d13cb8dd4165" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/e13f6757e267d687e20ec5b26ccfcbbe511cd8f4", - "reference": "e13f6757e267d687e20ec5b26ccfcbbe511cd8f4", + "url": "https://api.github.com/repos/symfony/process/zipball/318718453c2be58266f1a9e74063d13cb8dd4165", + "reference": "318718453c2be58266f1a9e74063d13cb8dd4165", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=8.1" }, "type": "library", "autoload": { @@ -1823,7 +1893,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.0.7" + "source": "https://github.com/symfony/process/tree/v6.1.0" }, "funding": [ { @@ -1839,24 +1909,24 @@ "type": "tidelift" } ], - "time": "2022-03-18T16:21:55+00:00" + "time": "2022-05-11T12:12:29+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.0.0", + "version": "v3.1.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "36715ebf9fb9db73db0cb24263c79077c6fe8603" + "reference": "d66cd8ab656780f62c4215b903a420eb86358957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/36715ebf9fb9db73db0cb24263c79077c6fe8603", - "reference": "36715ebf9fb9db73db0cb24263c79077c6fe8603", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d66cd8ab656780f62c4215b903a420eb86358957", + "reference": "d66cd8ab656780f62c4215b903a420eb86358957", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "psr/container": "^2.0" }, "conflict": { @@ -1868,7 +1938,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", @@ -1878,7 +1948,10 @@ "autoload": { "psr-4": { "Symfony\\Contracts\\Service\\": "" - } + }, + "exclude-from-classmap": [ + "/Test/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1905,7 +1978,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.0.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.1.0" }, "funding": [ { @@ -1921,24 +1994,24 @@ "type": "tidelift" } ], - "time": "2021-11-04T17:53:12+00:00" + "time": "2022-05-07T08:07:09+00:00" }, { "name": "symfony/string", - "version": "v6.0.3", + "version": "v6.1.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "522144f0c4c004c80d56fa47e40e17028e2eefc2" + "reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/522144f0c4c004c80d56fa47e40e17028e2eefc2", - "reference": "522144f0c4c004c80d56fa47e40e17028e2eefc2", + "url": "https://api.github.com/repos/symfony/string/zipball/d3edc75baf9f1d4f94879764dda2e1ac33499529", + "reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", @@ -1990,7 +2063,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.0.3" + "source": "https://github.com/symfony/string/tree/v6.1.0" }, "funding": [ { @@ -2006,24 +2079,24 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:55:41+00:00" + "time": "2022-04-22T08:18:23+00:00" }, { "name": "symfony/yaml", - "version": "v6.0.3", + "version": "v6.1.0", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "e77f3ea0b21141d771d4a5655faa54f692b34af5" + "reference": "84ce4f9d2d68f306f971a39d949d8f4b5550dba2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/e77f3ea0b21141d771d4a5655faa54f692b34af5", - "reference": "e77f3ea0b21141d771d4a5655faa54f692b34af5", + "url": "https://api.github.com/repos/symfony/yaml/zipball/84ce4f9d2d68f306f971a39d949d8f4b5550dba2", + "reference": "84ce4f9d2d68f306f971a39d949d8f4b5550dba2", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/polyfill-ctype": "^1.8" }, "conflict": { @@ -2064,7 +2137,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.0.3" + "source": "https://github.com/symfony/yaml/tree/v6.1.0" }, "funding": [ { @@ -2080,7 +2153,7 @@ "type": "tidelift" } ], - "time": "2022-01-26T17:23:29+00:00" + "time": "2022-04-15T14:25:02+00:00" } ], "aliases": [], @@ -2090,5 +2163,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.3.0" } From 4ca7b65a65198432ba393da7b46b96b140648272 Mon Sep 17 00:00:00 2001 From: "J. King" Date: Thu, 9 Jun 2022 21:21:17 -0400 Subject: [PATCH 02/16] Update dependencies --- composer.lock | 12 ++++++------ vendor-bin/daux/composer.lock | 26 +++++++++++++------------- vendor-bin/robo/composer.lock | 12 ++++++------ 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/composer.lock b/composer.lock index 816aff14..08a9d2bc 100644 --- a/composer.lock +++ b/composer.lock @@ -58,16 +58,16 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.5.6", + "version": "6.5.7", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "f092dd734083473658de3ee4bef093ed77d2689c" + "reference": "724562fa861e21a4071c652c8a159934e4f05592" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f092dd734083473658de3ee4bef093ed77d2689c", - "reference": "f092dd734083473658de3ee4bef093ed77d2689c", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/724562fa861e21a4071c652c8a159934e4f05592", + "reference": "724562fa861e21a4071c652c8a159934e4f05592", "shasum": "" }, "require": { @@ -153,7 +153,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/6.5.6" + "source": "https://github.com/guzzle/guzzle/tree/6.5.7" }, "funding": [ { @@ -169,7 +169,7 @@ "type": "tidelift" } ], - "time": "2022-05-25T13:19:12+00:00" + "time": "2022-06-09T21:36:50+00:00" }, { "name": "guzzlehttp/promises", diff --git a/vendor-bin/daux/composer.lock b/vendor-bin/daux/composer.lock index c5724031..8733ab35 100644 --- a/vendor-bin/daux/composer.lock +++ b/vendor-bin/daux/composer.lock @@ -83,16 +83,16 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.4.3", + "version": "7.4.4", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "74a8602c6faec9ef74b7a9391ac82c5e65b1cdab" + "reference": "e3ff079b22820c2029d4c2a87796b6a0b8716ad8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/74a8602c6faec9ef74b7a9391ac82c5e65b1cdab", - "reference": "74a8602c6faec9ef74b7a9391ac82c5e65b1cdab", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/e3ff079b22820c2029d4c2a87796b6a0b8716ad8", + "reference": "e3ff079b22820c2029d4c2a87796b6a0b8716ad8", "shasum": "" }, "require": { @@ -187,7 +187,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.4.3" + "source": "https://github.com/guzzle/guzzle/tree/7.4.4" }, "funding": [ { @@ -203,7 +203,7 @@ "type": "tidelift" } ], - "time": "2022-05-25T13:24:33+00:00" + "time": "2022-06-09T21:39:15+00:00" }, { "name": "guzzlehttp/promises", @@ -291,16 +291,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.2.1", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "c94a94f120803a18554c1805ef2e539f8285f9a2" + "reference": "83260bb50b8fc753c72d14dc1621a2dac31877ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/c94a94f120803a18554c1805ef2e539f8285f9a2", - "reference": "c94a94f120803a18554c1805ef2e539f8285f9a2", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/83260bb50b8fc753c72d14dc1621a2dac31877ee", + "reference": "83260bb50b8fc753c72d14dc1621a2dac31877ee", "shasum": "" }, "require": { @@ -324,7 +324,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -386,7 +386,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.2.1" + "source": "https://github.com/guzzle/psr7/tree/2.3.0" }, "funding": [ { @@ -402,7 +402,7 @@ "type": "tidelift" } ], - "time": "2022-03-20T21:55:58+00:00" + "time": "2022-06-09T08:26:02+00:00" }, { "name": "league/commonmark", diff --git a/vendor-bin/robo/composer.lock b/vendor-bin/robo/composer.lock index 21825423..b3aca916 100644 --- a/vendor-bin/robo/composer.lock +++ b/vendor-bin/robo/composer.lock @@ -1070,16 +1070,16 @@ }, { "name": "symfony/console", - "version": "v6.1.0", + "version": "v6.1.1", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c9646197ef43b0e2ff44af61e7f0571526fd4170" + "reference": "6187424023fbffcd757789aeb517c9161b1eabee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c9646197ef43b0e2ff44af61e7f0571526fd4170", - "reference": "c9646197ef43b0e2ff44af61e7f0571526fd4170", + "url": "https://api.github.com/repos/symfony/console/zipball/6187424023fbffcd757789aeb517c9161b1eabee", + "reference": "6187424023fbffcd757789aeb517c9161b1eabee", "shasum": "" }, "require": { @@ -1146,7 +1146,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.1.0" + "source": "https://github.com/symfony/console/tree/v6.1.1" }, "funding": [ { @@ -1162,7 +1162,7 @@ "type": "tidelift" } ], - "time": "2022-05-27T06:34:22+00:00" + "time": "2022-06-08T14:02:09+00:00" }, { "name": "symfony/deprecation-contracts", From 2557c22410bc63206196420a8ae0315726192b1e Mon Sep 17 00:00:00 2001 From: "J. King" Date: Wed, 22 Jun 2022 15:33:17 -0400 Subject: [PATCH 03/16] Update dependencies --- composer.lock | 30 +++++++++++++++--------------- vendor-bin/daux/composer.lock | 28 ++++++++++++++-------------- vendor-bin/phpunit/composer.lock | 13 ++++++------- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/composer.lock b/composer.lock index 08a9d2bc..ce4f8566 100644 --- a/composer.lock +++ b/composer.lock @@ -58,24 +58,24 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.5.7", + "version": "6.5.8", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "724562fa861e21a4071c652c8a159934e4f05592" + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/724562fa861e21a4071c652c8a159934e4f05592", - "reference": "724562fa861e21a4071c652c8a159934e4f05592", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981", "shasum": "" }, "require": { "ext-json": "*", "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.6.1", + "guzzlehttp/psr7": "^1.9", "php": ">=5.5", - "symfony/polyfill-intl-idn": "^1.17.0" + "symfony/polyfill-intl-idn": "^1.17" }, "require-dev": { "ext-curl": "*", @@ -153,7 +153,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/6.5.7" + "source": "https://github.com/guzzle/guzzle/tree/6.5.8" }, "funding": [ { @@ -169,7 +169,7 @@ "type": "tidelift" } ], - "time": "2022-06-09T21:36:50+00:00" + "time": "2022-06-20T22:16:07+00:00" }, { "name": "guzzlehttp/promises", @@ -257,16 +257,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.8.5", + "version": "1.9.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "337e3ad8e5716c15f9657bd214d16cc5e69df268" + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/337e3ad8e5716c15f9657bd214d16cc5e69df268", - "reference": "337e3ad8e5716c15f9657bd214d16cc5e69df268", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", "shasum": "" }, "require": { @@ -287,7 +287,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -347,7 +347,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/1.8.5" + "source": "https://github.com/guzzle/psr7/tree/1.9.0" }, "funding": [ { @@ -363,7 +363,7 @@ "type": "tidelift" } ], - "time": "2022-03-20T21:51:18+00:00" + "time": "2022-06-20T21:43:03+00:00" }, { "name": "hosteurope/password-generator", diff --git a/vendor-bin/daux/composer.lock b/vendor-bin/daux/composer.lock index 8733ab35..3c958282 100644 --- a/vendor-bin/daux/composer.lock +++ b/vendor-bin/daux/composer.lock @@ -83,22 +83,22 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.4.4", + "version": "7.4.5", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "e3ff079b22820c2029d4c2a87796b6a0b8716ad8" + "reference": "1dd98b0564cb3f6bd16ce683cb755f94c10fbd82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/e3ff079b22820c2029d4c2a87796b6a0b8716ad8", - "reference": "e3ff079b22820c2029d4c2a87796b6a0b8716ad8", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/1dd98b0564cb3f6bd16ce683cb755f94c10fbd82", + "reference": "1dd98b0564cb3f6bd16ce683cb755f94c10fbd82", "shasum": "" }, "require": { "ext-json": "*", "guzzlehttp/promises": "^1.5", - "guzzlehttp/psr7": "^1.8.3 || ^2.1", + "guzzlehttp/psr7": "^1.9 || ^2.4", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -187,7 +187,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.4.4" + "source": "https://github.com/guzzle/guzzle/tree/7.4.5" }, "funding": [ { @@ -203,7 +203,7 @@ "type": "tidelift" } ], - "time": "2022-06-09T21:39:15+00:00" + "time": "2022-06-20T22:16:13+00:00" }, { "name": "guzzlehttp/promises", @@ -291,16 +291,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.3.0", + "version": "2.4.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "83260bb50b8fc753c72d14dc1621a2dac31877ee" + "reference": "13388f00956b1503577598873fffb5ae994b5737" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/83260bb50b8fc753c72d14dc1621a2dac31877ee", - "reference": "83260bb50b8fc753c72d14dc1621a2dac31877ee", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/13388f00956b1503577598873fffb5ae994b5737", + "reference": "13388f00956b1503577598873fffb5ae994b5737", "shasum": "" }, "require": { @@ -324,7 +324,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-master": "2.4-dev" } }, "autoload": { @@ -386,7 +386,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.3.0" + "source": "https://github.com/guzzle/psr7/tree/2.4.0" }, "funding": [ { @@ -402,7 +402,7 @@ "type": "tidelift" } ], - "time": "2022-06-09T08:26:02+00:00" + "time": "2022-06-20T21:43:11+00:00" }, { "name": "league/commonmark", diff --git a/vendor-bin/phpunit/composer.lock b/vendor-bin/phpunit/composer.lock index 6dc54298..4658e04e 100644 --- a/vendor-bin/phpunit/composer.lock +++ b/vendor-bin/phpunit/composer.lock @@ -1160,16 +1160,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.20", + "version": "9.5.21", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba" + "reference": "0e32b76be457de00e83213528f6bb37e2a38fcb1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/12bc8879fb65aef2138b26fc633cb1e3620cffba", - "reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0e32b76be457de00e83213528f6bb37e2a38fcb1", + "reference": "0e32b76be457de00e83213528f6bb37e2a38fcb1", "shasum": "" }, "require": { @@ -1203,7 +1203,6 @@ "sebastian/version": "^3.0.2" }, "require-dev": { - "ext-pdo": "*", "phpspec/prophecy-phpunit": "^2.0.1" }, "suggest": { @@ -1247,7 +1246,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.20" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.21" }, "funding": [ { @@ -1259,7 +1258,7 @@ "type": "github" } ], - "time": "2022-04-01T12:37:26+00:00" + "time": "2022-06-19T12:14:25+00:00" }, { "name": "sebastian/cli-parser", From 560d4db139182d6d73d2ac76a95d5c46e6fb4a0e Mon Sep 17 00:00:00 2001 From: "J. King" Date: Thu, 4 Aug 2022 09:26:17 -0400 Subject: [PATCH 04/16] Remove Diactoros in favour of Guzzle PSR-7 For now this only adds convenience wrappers around Guzzle to somewhat emulate Diactoros (albeit with a different API). Code and tests will be adjusted in due course. --- composer.json | 2 +- composer.lock | 156 +------------------------------ lib/Misc/HTTP.php | 21 +++++ vendor-bin/csfixer/composer.lock | 109 ++++++++++----------- vendor-bin/daux/composer.lock | 88 ++++++++--------- vendor-bin/phpunit/composer.lock | 10 +- vendor-bin/robo/composer.lock | 116 +++++++++++------------ 7 files changed, 185 insertions(+), 317 deletions(-) diff --git a/composer.json b/composer.json index 97aedd38..38952d20 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "hosteurope/password-generator": "1.*", "docopt/docopt": "1.*", "jkingweb/druuid": "3.*", - "laminas/laminas-diactoros": "2.*", + "guzzlehttp/psr7": "1.*", "laminas/laminas-httphandlerrunner": "1.*" }, "require-dev": { diff --git a/composer.lock b/composer.lock index ce4f8566..15b9f4e5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c658930fbc56b2b2cf646e34c6a8d8d3", + "content-hash": "2671d9010a4ac73e877838baf3586df2", "packages": [ { "name": "docopt/docopt", @@ -537,105 +537,6 @@ }, "time": "2017-08-17T12:23:43+00:00" }, - { - "name": "laminas/laminas-diactoros", - "version": "2.4.1", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-diactoros.git", - "reference": "36ef09b73e884135d2059cc498c938e90821bb57" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/36ef09b73e884135d2059cc498c938e90821bb57", - "reference": "36ef09b73e884135d2059cc498c938e90821bb57", - "shasum": "" - }, - "require": { - "laminas/laminas-zendframework-bridge": "^1.0", - "php": "^7.1", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.0" - }, - "conflict": { - "phpspec/prophecy": "<1.9.0" - }, - "provide": { - "psr/http-factory-implementation": "1.0", - "psr/http-message-implementation": "1.0" - }, - "replace": { - "zendframework/zend-diactoros": "^2.2.1" - }, - "require-dev": { - "ext-curl": "*", - "ext-dom": "*", - "ext-gd": "*", - "ext-libxml": "*", - "http-interop/http-factory-tests": "^0.5.0", - "laminas/laminas-coding-standard": "~1.0.0", - "php-http/psr7-integration-tests": "^1.0", - "phpunit/phpunit": "^7.5.18" - }, - "type": "library", - "extra": { - "laminas": { - "config-provider": "Laminas\\Diactoros\\ConfigProvider", - "module": "Laminas\\Diactoros" - } - }, - "autoload": { - "files": [ - "src/functions/create_uploaded_file.php", - "src/functions/marshal_headers_from_sapi.php", - "src/functions/marshal_method_from_sapi.php", - "src/functions/marshal_protocol_version_from_sapi.php", - "src/functions/marshal_uri_from_sapi.php", - "src/functions/normalize_server.php", - "src/functions/normalize_uploaded_files.php", - "src/functions/parse_cookie_header.php", - "src/functions/create_uploaded_file.legacy.php", - "src/functions/marshal_headers_from_sapi.legacy.php", - "src/functions/marshal_method_from_sapi.legacy.php", - "src/functions/marshal_protocol_version_from_sapi.legacy.php", - "src/functions/marshal_uri_from_sapi.legacy.php", - "src/functions/normalize_server.legacy.php", - "src/functions/normalize_uploaded_files.legacy.php", - "src/functions/parse_cookie_header.legacy.php" - ], - "psr-4": { - "Laminas\\Diactoros\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "PSR HTTP Message implementations", - "homepage": "https://laminas.dev", - "keywords": [ - "http", - "laminas", - "psr", - "psr-17", - "psr-7" - ], - "support": { - "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-diactoros/", - "forum": "https://discourse.laminas.dev", - "issues": "https://github.com/laminas/laminas-diactoros/issues", - "rss": "https://github.com/laminas/laminas-diactoros/releases.atom", - "source": "https://github.com/laminas/laminas-diactoros" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2020-09-03T14:29:41+00:00" - }, { "name": "laminas/laminas-httphandlerrunner", "version": "1.2.0", @@ -892,61 +793,6 @@ }, "time": "2020-09-15T07:28:23+00:00" }, - { - "name": "psr/http-factory", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-factory.git", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", - "shasum": "" - }, - "require": { - "php": ">=7.0.0", - "psr/http-message": "^1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interfaces for PSR-7 HTTP message factories", - "keywords": [ - "factory", - "http", - "message", - "psr", - "psr-17", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-factory/tree/master" - }, - "time": "2019-04-30T12:38:16+00:00" - }, { "name": "psr/http-message", "version": "1.0.1", diff --git a/lib/Misc/HTTP.php b/lib/Misc/HTTP.php index ac415062..cd78b380 100644 --- a/lib/Misc/HTTP.php +++ b/lib/Misc/HTTP.php @@ -7,6 +7,8 @@ declare(strict_types=1); namespace JKingWeb\Arsse\Misc; use Psr\Http\Message\MessageInterface; +use Psr\Http\Message\ResponseInterface; +use GuzzleHttp\Psr7\Response; class HTTP { public static function matchType(MessageInterface $msg, string ...$type): bool { @@ -19,4 +21,23 @@ class HTTP { } return false; } + + public static function respEmpty(int $status, ?array $headers = []): ResponseInterface { + return new Response($status, $headers ?? []); + } + + public static function respJson($body, int $status = 200, ?array $headers = []): ResponseInterface { + $headers = ($headers ?? []) + ['Content-Type' => "application/json"]; + return new Response($status, $headers, json_encode($body, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE)); + } + + public static function respText(string $body, int $status = 200, ?array $headers = []): ResponseInterface { + $headers = ($headers ?? []) + ['Content-Type' => "text/plain; charset=UTF-8"]; + return new Response($status, $headers, $body); + } + + public static function respXml(string $body, int $status = 200, ?array $headers = []): ResponseInterface { + $headers = ($headers ?? []) + ['Content-Type' => "application/xml; charset=UTF-8"]; + return new Response($status, $headers, $body); + } } diff --git a/vendor-bin/csfixer/composer.lock b/vendor-bin/csfixer/composer.lock index 1f322d06..e678c6e2 100644 --- a/vendor-bin/csfixer/composer.lock +++ b/vendor-bin/csfixer/composer.lock @@ -227,16 +227,16 @@ }, { "name": "doctrine/annotations", - "version": "1.13.2", + "version": "1.13.3", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "5b668aef16090008790395c02c893b1ba13f7e08" + "reference": "648b0343343565c4a056bfc8392201385e8d89f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/5b668aef16090008790395c02c893b1ba13f7e08", - "reference": "5b668aef16090008790395c02c893b1ba13f7e08", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/648b0343343565c4a056bfc8392201385e8d89f0", + "reference": "648b0343343565c4a056bfc8392201385e8d89f0", "shasum": "" }, "require": { @@ -248,9 +248,10 @@ "require-dev": { "doctrine/cache": "^1.11 || ^2.0", "doctrine/coding-standard": "^6.0 || ^8.1", - "phpstan/phpstan": "^0.12.20", + "phpstan/phpstan": "^1.4.10 || ^1.8.0", "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", - "symfony/cache": "^4.4 || ^5.2" + "symfony/cache": "^4.4 || ^5.2", + "vimeo/psalm": "^4.10" }, "type": "library", "autoload": { @@ -293,9 +294,9 @@ ], "support": { "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.13.2" + "source": "https://github.com/doctrine/annotations/tree/1.13.3" }, - "time": "2021-08-05T19:00:23+00:00" + "time": "2022-07-02T10:48:51+00:00" }, { "name": "doctrine/lexer", @@ -741,16 +742,16 @@ }, { "name": "symfony/console", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb" + "reference": "535846c7ee6bc4dd027ca0d93220601456734b10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/829d5d1bf60b2efeb0887b7436873becc71a45eb", - "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb", + "url": "https://api.github.com/repos/symfony/console/zipball/535846c7ee6bc4dd027ca0d93220601456734b10", + "reference": "535846c7ee6bc4dd027ca0d93220601456734b10", "shasum": "" }, "require": { @@ -820,7 +821,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.9" + "source": "https://github.com/symfony/console/tree/v5.4.11" }, "funding": [ { @@ -836,11 +837,11 @@ "type": "tidelift" } ], - "time": "2022-05-18T06:17:34+00:00" + "time": "2022-07-22T10:42:43+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.1.0", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", @@ -887,7 +888,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.1" }, "funding": [ { @@ -992,7 +993,7 @@ }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.1.0", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", @@ -1051,7 +1052,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.1.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.1.1" }, "funding": [ { @@ -1071,16 +1072,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "36a017fa4cce1eff1b8e8129ff53513abcef05ba" + "reference": "6699fb0228d1bc35b12aed6dd5e7455457609ddd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/36a017fa4cce1eff1b8e8129ff53513abcef05ba", - "reference": "36a017fa4cce1eff1b8e8129ff53513abcef05ba", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/6699fb0228d1bc35b12aed6dd5e7455457609ddd", + "reference": "6699fb0228d1bc35b12aed6dd5e7455457609ddd", "shasum": "" }, "require": { @@ -1115,7 +1116,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.9" + "source": "https://github.com/symfony/filesystem/tree/v5.4.11" }, "funding": [ { @@ -1131,20 +1132,20 @@ "type": "tidelift" } ], - "time": "2022-05-20T13:55:35+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/finder", - "version": "v5.4.8", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9" + "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/9b630f3427f3ebe7cd346c277a1408b00249dad9", - "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9", + "url": "https://api.github.com/repos/symfony/finder/zipball/7872a66f57caffa2916a584db1aa7f12adc76f8c", + "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c", "shasum": "" }, "require": { @@ -1178,7 +1179,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.8" + "source": "https://github.com/symfony/finder/tree/v5.4.11" }, "funding": [ { @@ -1194,20 +1195,20 @@ "type": "tidelift" } ], - "time": "2022-04-15T08:07:45+00:00" + "time": "2022-07-29T07:37:50+00:00" }, { "name": "symfony/options-resolver", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "cc1147cb11af1b43f503ac18f31aa3bec213aba8" + "reference": "54f14e36aa73cb8f7261d7686691fd4d75ea2690" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/cc1147cb11af1b43f503ac18f31aa3bec213aba8", - "reference": "cc1147cb11af1b43f503ac18f31aa3bec213aba8", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/54f14e36aa73cb8f7261d7686691fd4d75ea2690", + "reference": "54f14e36aa73cb8f7261d7686691fd4d75ea2690", "shasum": "" }, "require": { @@ -1247,7 +1248,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v5.4.3" + "source": "https://github.com/symfony/options-resolver/tree/v5.4.11" }, "funding": [ { @@ -1263,7 +1264,7 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/polyfill-ctype", @@ -1903,16 +1904,16 @@ }, { "name": "symfony/process", - "version": "v5.4.8", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3" + "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", - "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", + "url": "https://api.github.com/repos/symfony/process/zipball/6e75fe6874cbc7e4773d049616ab450eff537bf1", + "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1", "shasum": "" }, "require": { @@ -1945,7 +1946,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.8" + "source": "https://github.com/symfony/process/tree/v5.4.11" }, "funding": [ { @@ -1961,20 +1962,20 @@ "type": "tidelift" } ], - "time": "2022-04-08T05:07:18+00:00" + "time": "2022-06-27T16:58:25+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.1.0", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "d66cd8ab656780f62c4215b903a420eb86358957" + "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d66cd8ab656780f62c4215b903a420eb86358957", - "reference": "d66cd8ab656780f62c4215b903a420eb86358957", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/925e713fe8fcacf6bc05e936edd8dd5441a21239", + "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239", "shasum": "" }, "require": { @@ -2030,7 +2031,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.1.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.1.1" }, "funding": [ { @@ -2046,7 +2047,7 @@ "type": "tidelift" } ], - "time": "2022-05-07T08:07:09+00:00" + "time": "2022-05-30T19:18:58+00:00" }, { "name": "symfony/stopwatch", @@ -2112,16 +2113,16 @@ }, { "name": "symfony/string", - "version": "v6.1.0", + "version": "v6.1.3", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529" + "reference": "f35241f45c30bcd9046af2bb200a7086f70e1d6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/d3edc75baf9f1d4f94879764dda2e1ac33499529", - "reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529", + "url": "https://api.github.com/repos/symfony/string/zipball/f35241f45c30bcd9046af2bb200a7086f70e1d6b", + "reference": "f35241f45c30bcd9046af2bb200a7086f70e1d6b", "shasum": "" }, "require": { @@ -2177,7 +2178,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.1.0" + "source": "https://github.com/symfony/string/tree/v6.1.3" }, "funding": [ { @@ -2193,7 +2194,7 @@ "type": "tidelift" } ], - "time": "2022-04-22T08:18:23+00:00" + "time": "2022-07-27T15:50:51+00:00" } ], "aliases": [], diff --git a/vendor-bin/daux/composer.lock b/vendor-bin/daux/composer.lock index 3c958282..5b50eca4 100644 --- a/vendor-bin/daux/composer.lock +++ b/vendor-bin/daux/composer.lock @@ -898,16 +898,16 @@ }, { "name": "symfony/console", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb" + "reference": "535846c7ee6bc4dd027ca0d93220601456734b10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/829d5d1bf60b2efeb0887b7436873becc71a45eb", - "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb", + "url": "https://api.github.com/repos/symfony/console/zipball/535846c7ee6bc4dd027ca0d93220601456734b10", + "reference": "535846c7ee6bc4dd027ca0d93220601456734b10", "shasum": "" }, "require": { @@ -977,7 +977,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.9" + "source": "https://github.com/symfony/console/tree/v5.4.11" }, "funding": [ { @@ -993,11 +993,11 @@ "type": "tidelift" } ], - "time": "2022-05-18T06:17:34+00:00" + "time": "2022-07-22T10:42:43+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.1.0", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", @@ -1044,7 +1044,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.1" }, "funding": [ { @@ -1064,16 +1064,16 @@ }, { "name": "symfony/http-foundation", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "6b0d0e4aca38d57605dcd11e2416994b38774522" + "reference": "0a5868e0999e9d47859ba3d918548ff6943e6389" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6b0d0e4aca38d57605dcd11e2416994b38774522", - "reference": "6b0d0e4aca38d57605dcd11e2416994b38774522", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/0a5868e0999e9d47859ba3d918548ff6943e6389", + "reference": "0a5868e0999e9d47859ba3d918548ff6943e6389", "shasum": "" }, "require": { @@ -1117,7 +1117,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.9" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.11" }, "funding": [ { @@ -1133,20 +1133,20 @@ "type": "tidelift" } ], - "time": "2022-05-17T15:07:29+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/mime", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "2b3802a24e48d0cfccf885173d2aac91e73df92e" + "reference": "3cd175cdcdb6db2e589e837dd46aff41027d9830" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/2b3802a24e48d0cfccf885173d2aac91e73df92e", - "reference": "2b3802a24e48d0cfccf885173d2aac91e73df92e", + "url": "https://api.github.com/repos/symfony/mime/zipball/3cd175cdcdb6db2e589e837dd46aff41027d9830", + "reference": "3cd175cdcdb6db2e589e837dd46aff41027d9830", "shasum": "" }, "require": { @@ -1200,7 +1200,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.4.9" + "source": "https://github.com/symfony/mime/tree/v5.4.11" }, "funding": [ { @@ -1216,7 +1216,7 @@ "type": "tidelift" } ], - "time": "2022-05-21T10:24:18+00:00" + "time": "2022-07-20T11:34:24+00:00" }, { "name": "symfony/polyfill-ctype", @@ -1962,16 +1962,16 @@ }, { "name": "symfony/process", - "version": "v5.4.8", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3" + "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", - "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", + "url": "https://api.github.com/repos/symfony/process/zipball/6e75fe6874cbc7e4773d049616ab450eff537bf1", + "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1", "shasum": "" }, "require": { @@ -2004,7 +2004,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.8" + "source": "https://github.com/symfony/process/tree/v5.4.11" }, "funding": [ { @@ -2020,20 +2020,20 @@ "type": "tidelift" } ], - "time": "2022-04-08T05:07:18+00:00" + "time": "2022-06-27T16:58:25+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.1.0", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "d66cd8ab656780f62c4215b903a420eb86358957" + "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d66cd8ab656780f62c4215b903a420eb86358957", - "reference": "d66cd8ab656780f62c4215b903a420eb86358957", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/925e713fe8fcacf6bc05e936edd8dd5441a21239", + "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239", "shasum": "" }, "require": { @@ -2089,7 +2089,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.1.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.1.1" }, "funding": [ { @@ -2105,20 +2105,20 @@ "type": "tidelift" } ], - "time": "2022-05-07T08:07:09+00:00" + "time": "2022-05-30T19:18:58+00:00" }, { "name": "symfony/string", - "version": "v6.1.0", + "version": "v6.1.3", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529" + "reference": "f35241f45c30bcd9046af2bb200a7086f70e1d6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/d3edc75baf9f1d4f94879764dda2e1ac33499529", - "reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529", + "url": "https://api.github.com/repos/symfony/string/zipball/f35241f45c30bcd9046af2bb200a7086f70e1d6b", + "reference": "f35241f45c30bcd9046af2bb200a7086f70e1d6b", "shasum": "" }, "require": { @@ -2174,7 +2174,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.1.0" + "source": "https://github.com/symfony/string/tree/v6.1.3" }, "funding": [ { @@ -2190,20 +2190,20 @@ "type": "tidelift" } ], - "time": "2022-04-22T08:18:23+00:00" + "time": "2022-07-27T15:50:51+00:00" }, { "name": "symfony/yaml", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "e80f87d2c9495966768310fc531b487ce64237a2" + "reference": "05d4ea560f3402c6c116afd99fdc66e60eda227e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/e80f87d2c9495966768310fc531b487ce64237a2", - "reference": "e80f87d2c9495966768310fc531b487ce64237a2", + "url": "https://api.github.com/repos/symfony/yaml/zipball/05d4ea560f3402c6c116afd99fdc66e60eda227e", + "reference": "05d4ea560f3402c6c116afd99fdc66e60eda227e", "shasum": "" }, "require": { @@ -2249,7 +2249,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.4.3" + "source": "https://github.com/symfony/yaml/tree/v5.4.11" }, "funding": [ { @@ -2265,7 +2265,7 @@ "type": "tidelift" } ], - "time": "2022-01-26T16:32:32+00:00" + "time": "2022-06-27T16:58:25+00:00" }, { "name": "webuni/front-matter", diff --git a/vendor-bin/phpunit/composer.lock b/vendor-bin/phpunit/composer.lock index 4658e04e..8b04348b 100644 --- a/vendor-bin/phpunit/composer.lock +++ b/vendor-bin/phpunit/composer.lock @@ -338,16 +338,16 @@ }, { "name": "mikey179/vfsstream", - "version": "v1.6.10", + "version": "v1.6.11", "source": { "type": "git", "url": "https://github.com/bovigo/vfsStream.git", - "reference": "250c0825537d501e327df879fb3d4cd751933b85" + "reference": "17d16a85e6c26ce1f3e2fa9ceeacdc2855db1e9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bovigo/vfsStream/zipball/250c0825537d501e327df879fb3d4cd751933b85", - "reference": "250c0825537d501e327df879fb3d4cd751933b85", + "url": "https://api.github.com/repos/bovigo/vfsStream/zipball/17d16a85e6c26ce1f3e2fa9ceeacdc2855db1e9f", + "reference": "17d16a85e6c26ce1f3e2fa9ceeacdc2855db1e9f", "shasum": "" }, "require": { @@ -385,7 +385,7 @@ "source": "https://github.com/bovigo/vfsStream/tree/master", "wiki": "https://github.com/bovigo/vfsStream/wiki" }, - "time": "2021-09-25T08:05:01+00:00" + "time": "2022-02-23T02:02:42+00:00" }, { "name": "myclabs/deep-copy", diff --git a/vendor-bin/robo/composer.lock b/vendor-bin/robo/composer.lock index b3aca916..a56d7e69 100644 --- a/vendor-bin/robo/composer.lock +++ b/vendor-bin/robo/composer.lock @@ -90,16 +90,16 @@ }, { "name": "consolidation/annotated-command", - "version": "4.5.5", + "version": "4.5.6", "source": { "type": "git", "url": "https://github.com/consolidation/annotated-command.git", - "reference": "67cea8e8e7656b74da651ea6f49321853996c0fd" + "reference": "3968070538761628546270935f0733a0cc408e1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/67cea8e8e7656b74da651ea6f49321853996c0fd", - "reference": "67cea8e8e7656b74da651ea6f49321853996c0fd", + "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/3968070538761628546270935f0733a0cc408e1f", + "reference": "3968070538761628546270935f0733a0cc408e1f", "shasum": "" }, "require": { @@ -140,22 +140,22 @@ "description": "Initialize Symfony Console commands from annotated command class methods.", "support": { "issues": "https://github.com/consolidation/annotated-command/issues", - "source": "https://github.com/consolidation/annotated-command/tree/4.5.5" + "source": "https://github.com/consolidation/annotated-command/tree/4.5.6" }, - "time": "2022-04-26T16:18:25+00:00" + "time": "2022-06-22T20:17:12+00:00" }, { "name": "consolidation/config", - "version": "2.1.0", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/consolidation/config.git", - "reference": "0c15841b2bf60d9af1ce29884673e7d9d50c3b75" + "reference": "dae810c162f0e799ea3f35cc2f40b0797b6e4d26" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/config/zipball/0c15841b2bf60d9af1ce29884673e7d9d50c3b75", - "reference": "0c15841b2bf60d9af1ce29884673e7d9d50c3b75", + "url": "https://api.github.com/repos/consolidation/config/zipball/dae810c162f0e799ea3f35cc2f40b0797b6e4d26", + "reference": "dae810c162f0e799ea3f35cc2f40b0797b6e4d26", "shasum": "" }, "require": { @@ -200,9 +200,9 @@ "description": "Provide configuration services for a commandline tool.", "support": { "issues": "https://github.com/consolidation/config/issues", - "source": "https://github.com/consolidation/config/tree/2.1.0" + "source": "https://github.com/consolidation/config/tree/2.1.1" }, - "time": "2022-02-24T00:32:42+00:00" + "time": "2022-06-22T19:59:34+00:00" }, { "name": "consolidation/log", @@ -1070,16 +1070,16 @@ }, { "name": "symfony/console", - "version": "v6.1.1", + "version": "v6.1.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "6187424023fbffcd757789aeb517c9161b1eabee" + "reference": "43fcb5c5966b43c56bcfa481368d90d748936ab8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/6187424023fbffcd757789aeb517c9161b1eabee", - "reference": "6187424023fbffcd757789aeb517c9161b1eabee", + "url": "https://api.github.com/repos/symfony/console/zipball/43fcb5c5966b43c56bcfa481368d90d748936ab8", + "reference": "43fcb5c5966b43c56bcfa481368d90d748936ab8", "shasum": "" }, "require": { @@ -1146,7 +1146,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.1.1" + "source": "https://github.com/symfony/console/tree/v6.1.3" }, "funding": [ { @@ -1162,11 +1162,11 @@ "type": "tidelift" } ], - "time": "2022-06-08T14:02:09+00:00" + "time": "2022-07-22T14:17:57+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.1.0", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", @@ -1213,7 +1213,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.1" }, "funding": [ { @@ -1316,7 +1316,7 @@ }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.1.0", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", @@ -1375,7 +1375,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.1.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.1.1" }, "funding": [ { @@ -1395,16 +1395,16 @@ }, { "name": "symfony/filesystem", - "version": "v6.1.0", + "version": "v6.1.3", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "3132d2f43ca799c2aa099f9738d98228c56baa5d" + "reference": "c780e677cddda78417fa5187a7c6cd2f21110db9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/3132d2f43ca799c2aa099f9738d98228c56baa5d", - "reference": "3132d2f43ca799c2aa099f9738d98228c56baa5d", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/c780e677cddda78417fa5187a7c6cd2f21110db9", + "reference": "c780e677cddda78417fa5187a7c6cd2f21110db9", "shasum": "" }, "require": { @@ -1438,7 +1438,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.1.0" + "source": "https://github.com/symfony/filesystem/tree/v6.1.3" }, "funding": [ { @@ -1454,20 +1454,20 @@ "type": "tidelift" } ], - "time": "2022-05-21T13:34:40+00:00" + "time": "2022-07-20T14:45:06+00:00" }, { "name": "symfony/finder", - "version": "v6.1.0", + "version": "v6.1.3", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "45b8beb69d6eb3b05a65689ebfd4222326773f8f" + "reference": "39696bff2c2970b3779a5cac7bf9f0b88fc2b709" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/45b8beb69d6eb3b05a65689ebfd4222326773f8f", - "reference": "45b8beb69d6eb3b05a65689ebfd4222326773f8f", + "url": "https://api.github.com/repos/symfony/finder/zipball/39696bff2c2970b3779a5cac7bf9f0b88fc2b709", + "reference": "39696bff2c2970b3779a5cac7bf9f0b88fc2b709", "shasum": "" }, "require": { @@ -1502,7 +1502,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.1.0" + "source": "https://github.com/symfony/finder/tree/v6.1.3" }, "funding": [ { @@ -1518,7 +1518,7 @@ "type": "tidelift" } ], - "time": "2022-04-15T08:08:08+00:00" + "time": "2022-07-29T07:42:06+00:00" }, { "name": "symfony/polyfill-ctype", @@ -1852,16 +1852,16 @@ }, { "name": "symfony/process", - "version": "v6.1.0", + "version": "v6.1.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "318718453c2be58266f1a9e74063d13cb8dd4165" + "reference": "a6506e99cfad7059b1ab5cab395854a0a0c21292" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/318718453c2be58266f1a9e74063d13cb8dd4165", - "reference": "318718453c2be58266f1a9e74063d13cb8dd4165", + "url": "https://api.github.com/repos/symfony/process/zipball/a6506e99cfad7059b1ab5cab395854a0a0c21292", + "reference": "a6506e99cfad7059b1ab5cab395854a0a0c21292", "shasum": "" }, "require": { @@ -1893,7 +1893,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.1.0" + "source": "https://github.com/symfony/process/tree/v6.1.3" }, "funding": [ { @@ -1909,20 +1909,20 @@ "type": "tidelift" } ], - "time": "2022-05-11T12:12:29+00:00" + "time": "2022-06-27T17:24:16+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.1.0", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "d66cd8ab656780f62c4215b903a420eb86358957" + "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d66cd8ab656780f62c4215b903a420eb86358957", - "reference": "d66cd8ab656780f62c4215b903a420eb86358957", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/925e713fe8fcacf6bc05e936edd8dd5441a21239", + "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239", "shasum": "" }, "require": { @@ -1978,7 +1978,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.1.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.1.1" }, "funding": [ { @@ -1994,20 +1994,20 @@ "type": "tidelift" } ], - "time": "2022-05-07T08:07:09+00:00" + "time": "2022-05-30T19:18:58+00:00" }, { "name": "symfony/string", - "version": "v6.1.0", + "version": "v6.1.3", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529" + "reference": "f35241f45c30bcd9046af2bb200a7086f70e1d6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/d3edc75baf9f1d4f94879764dda2e1ac33499529", - "reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529", + "url": "https://api.github.com/repos/symfony/string/zipball/f35241f45c30bcd9046af2bb200a7086f70e1d6b", + "reference": "f35241f45c30bcd9046af2bb200a7086f70e1d6b", "shasum": "" }, "require": { @@ -2063,7 +2063,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.1.0" + "source": "https://github.com/symfony/string/tree/v6.1.3" }, "funding": [ { @@ -2079,20 +2079,20 @@ "type": "tidelift" } ], - "time": "2022-04-22T08:18:23+00:00" + "time": "2022-07-27T15:50:51+00:00" }, { "name": "symfony/yaml", - "version": "v6.1.0", + "version": "v6.1.3", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "84ce4f9d2d68f306f971a39d949d8f4b5550dba2" + "reference": "cc48dd42ae1201abced04ae38284e23ce2d2d8f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/84ce4f9d2d68f306f971a39d949d8f4b5550dba2", - "reference": "84ce4f9d2d68f306f971a39d949d8f4b5550dba2", + "url": "https://api.github.com/repos/symfony/yaml/zipball/cc48dd42ae1201abced04ae38284e23ce2d2d8f3", + "reference": "cc48dd42ae1201abced04ae38284e23ce2d2d8f3", "shasum": "" }, "require": { @@ -2137,7 +2137,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.1.0" + "source": "https://github.com/symfony/yaml/tree/v6.1.3" }, "funding": [ { @@ -2153,7 +2153,7 @@ "type": "tidelift" } ], - "time": "2022-04-15T14:25:02+00:00" + "time": "2022-07-20T14:45:06+00:00" } ], "aliases": [], From 6c0183faea1a91a7ffd26d65e8d1e4f1baa4fb54 Mon Sep 17 00:00:00 2001 From: "J. King" Date: Thu, 4 Aug 2022 22:04:39 -0400 Subject: [PATCH 05/16] Replace instances of Diactoros' EmptyResponse --- lib/REST.php | 6 +- lib/REST/Fever/API.php | 11 +- lib/REST/Miniflux/Status.php | 8 +- lib/REST/Miniflux/V1.php | 34 +++--- lib/REST/NextcloudNews/V1_2.php | 115 +++++++++--------- lib/REST/NextcloudNews/Versions.php | 8 +- lib/REST/TinyTinyRSS/API.php | 10 +- lib/REST/TinyTinyRSS/Icon.php | 14 +-- tests/cases/REST/Fever/TestAPI.php | 10 +- tests/cases/REST/Miniflux/TestStatus.php | 12 +- tests/cases/REST/Miniflux/TestV1.php | 38 +++--- tests/cases/REST/NextcloudNews/TestV1_2.php | 112 ++++++++--------- .../cases/REST/NextcloudNews/TestVersions.php | 8 +- tests/cases/REST/TestREST.php | 40 +++--- tests/cases/REST/TinyTinyRSS/TestAPI.php | 14 +-- tests/cases/REST/TinyTinyRSS/TestIcon.php | 24 ++-- 16 files changed, 231 insertions(+), 233 deletions(-) diff --git a/lib/REST.php b/lib/REST.php index f7818e56..56dbf11c 100644 --- a/lib/REST.php +++ b/lib/REST.php @@ -7,11 +7,11 @@ declare(strict_types=1); namespace JKingWeb\Arsse; use JKingWeb\Arsse\Misc\URL; +use JKingWeb\Arsse\Misc\HTTP; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\ServerRequestFactory; -use Laminas\Diactoros\Response\EmptyResponse; class REST { public const API_LIST = [ @@ -101,7 +101,7 @@ class REST { $res = $drv->dispatch($req); } } catch (REST\Exception501 $e) { - $res = new EmptyResponse(501); + $res = HTTP::respEmpty(501); } // modify the response so that it has all the required metadata return $this->normalizeResponse($res, $req); @@ -180,7 +180,7 @@ class REST { } // if the response is to a HEAD request, the body should be omitted if ($req && $req->getMethod() === "HEAD") { - $res = new EmptyResponse($res->getStatusCode(), $res->getHeaders()); + $res = HTTP::respEmpty($res->getStatusCode(), $res->getHeaders()); } // if an Allow header field is present, normalize it if ($res->hasHeader("Allow")) { diff --git a/lib/REST/Fever/API.php b/lib/REST/Fever/API.php index 7ad69ba5..72f3e9b7 100644 --- a/lib/REST/Fever/API.php +++ b/lib/REST/Fever/API.php @@ -10,13 +10,12 @@ use JKingWeb\Arsse\Arsse; use JKingWeb\Arsse\Context\Context; use JKingWeb\Arsse\Misc\ValueInfo as V; use JKingWeb\Arsse\Misc\Date; -use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\Misc\HTTP; +use JKingWeb\Arsse\Db\ExceptionInput; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse; use Laminas\Diactoros\Response\XmlResponse; -use Laminas\Diactoros\Response\EmptyResponse; class API extends \JKingWeb\Arsse\REST\AbstractHandler { public const LEVEL = 3; @@ -62,11 +61,11 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { $P = $this->normalizeInputPost($req->getParsedBody() ?? []); if (!isset($G['api'])) { // the original would have shown the Fever UI in the absence of the "api" parameter, but we'll return 404 - return new EmptyResponse(404); + return HTTP::respEmpty(404); } switch ($req->getMethod()) { case "OPTIONS": - return new EmptyResponse(204, [ + return HTTP::respEmpty(204, [ 'Allow' => "POST", 'Accept' => implode(", ", self::ACCEPTED_TYPES), ]); @@ -82,7 +81,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { $out['auth'] = 1; } elseif (Arsse::$conf->userHTTPAuthRequired || Arsse::$conf->userPreAuth || $req->getAttribute("authenticationFailed", false)) { // otherwise if HTTP authentication failed or is required, deny access at the HTTP level - return new EmptyResponse(401); + return HTTP::respEmpty(401); } // produce a full response if authenticated or a basic response otherwise if ($this->logIn(strtolower($P['api_key'] ?? ""))) { @@ -93,7 +92,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { // return the result, possibly formatted as XML return $this->formatResponse($out, ($G['api'] === "xml")); default: - return new EmptyResponse(405, ['Allow' => "OPTIONS,POST"]); + return HTTP::respEmpty(405, ['Allow' => "OPTIONS,POST"]); } } diff --git a/lib/REST/Miniflux/Status.php b/lib/REST/Miniflux/Status.php index 367a7a65..c829193b 100644 --- a/lib/REST/Miniflux/Status.php +++ b/lib/REST/Miniflux/Status.php @@ -6,9 +6,9 @@ declare(strict_types=1); namespace JKingWeb\Arsse\REST\Miniflux; +use JKingWeb\Arsse\Misc\HTTP; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\EmptyResponse; use Laminas\Diactoros\Response\TextResponse; class Status extends \JKingWeb\Arsse\REST\AbstractHandler { @@ -18,13 +18,13 @@ class Status extends \JKingWeb\Arsse\REST\AbstractHandler { public function dispatch(ServerRequestInterface $req): ResponseInterface { $target = parse_url($req->getRequestTarget())['path'] ?? ""; if (!in_array($target, ["/version", "/healthcheck"])) { - return new EmptyResponse(404); + return HTTP::respEmpty(404); } $method = $req->getMethod(); if ($method === "OPTIONS") { - return new EmptyResponse(204, ['Allow' => "HEAD, GET"]); + return HTTP::respEmpty(204, ['Allow' => "HEAD, GET"]); } elseif ($method !== "GET") { - return new EmptyResponse(405, ['Allow' => "HEAD, GET"]); + return HTTP::respEmpty(405, ['Allow' => "HEAD, GET"]); } $out = ""; if ($target === "/version") { diff --git a/lib/REST/Miniflux/V1.php b/lib/REST/Miniflux/V1.php index 6897472f..4ed828a9 100644 --- a/lib/REST/Miniflux/V1.php +++ b/lib/REST/Miniflux/V1.php @@ -19,6 +19,7 @@ use JKingWeb\Arsse\ImportExport\OPML; use JKingWeb\Arsse\ImportExport\Exception as ImportException; use JKingWeb\Arsse\Misc\Date; use JKingWeb\Arsse\Misc\URL; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Misc\ValueInfo as V; use JKingWeb\Arsse\REST\Exception; use JKingWeb\Arsse\Rule\Rule; @@ -26,7 +27,6 @@ use JKingWeb\Arsse\User\ExceptionConflict; use JKingWeb\Arsse\User\Exception as UserException; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\EmptyResponse; use Laminas\Diactoros\Response\JsonResponse as Response; use Laminas\Diactoros\Response\TextResponse as GenericResponse; use Laminas\Diactoros\Uri; @@ -295,10 +295,10 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { // @codeCoverageIgnoreStart } catch (Exception $e) { // if there was a REST exception return 400 - return new EmptyResponse(400); + return HTTP::respEmpty(400); } catch (AbstractException $e) { // if there was any other Arsse exception return 500 - return new EmptyResponse(500); + return HTTP::respEmpty(500); } // @codeCoverageIgnoreEnd } @@ -317,11 +317,11 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { return self::CALLS[$url][$method]; } else { // otherwise return 405 - return new EmptyResponse(405, ['Allow' => implode(", ", array_keys(self::CALLS[$url]))]); + return HTTP::respEmpty(405, ['Allow' => implode(", ", array_keys(self::CALLS[$url]))]); } } else { // if the path is not supported, return 404 - return new EmptyResponse(404); + return HTTP::respEmpty(404); } } @@ -451,13 +451,13 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { if (in_array("GET", $allowed)) { array_unshift($allowed, "HEAD"); } - return new EmptyResponse(204, [ + return HTTP::respEmpty(204, [ 'Allow' => implode(", ", $allowed), 'Accept' => implode(", ", $url === "/import" ? self::ACCEPTED_TYPES_OPML : self::ACCEPTED_TYPES_JSON), ]); } else { // if the path is not supported, return 404 - return new EmptyResponse(404); + return HTTP::respEmpty(404); } } @@ -637,7 +637,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionConflict $e) { return new ErrorResponse("404", 404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } /** Returns a useful subset of user metadata @@ -728,7 +728,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function transformFeed(array $sub, int $uid, string $rootName, \DateTimeZone $tz): array { @@ -866,7 +866,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { protected function deleteFeed(array $path): ResponseInterface { try { Arsse::$db->subscriptionRemove(Arsse::$user->id, (int) $path[1]); - return new EmptyResponse(204); + return HTTP::respEmpty(204); } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } @@ -1104,7 +1104,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } assert(isset($in), new \Exception("Unknown status specified")); Arsse::$db->articleMark(Arsse::$user->id, $in, (new Context)->articles($data['entry_ids'])); - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function massRead(Context $c): void { @@ -1118,7 +1118,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { return new ErrorResponse("403", 403); } $this->massRead(new Context); - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function markFeed(array $path): ResponseInterface { @@ -1127,7 +1127,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function markCategory(array $path): ResponseInterface { @@ -1144,7 +1144,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function toggleEntryBookmark(array $path): ResponseInterface { @@ -1162,7 +1162,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function refreshFeed(array $path): ResponseInterface { @@ -1172,13 +1172,13 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function refreshAllFeeds(): ResponseInterface { // NOTE: This is a no-op // It could be implemented, but the need is considered low since we use a dynamic schedule always - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function opmlImport(string $data): ResponseInterface { diff --git a/lib/REST/NextcloudNews/V1_2.php b/lib/REST/NextcloudNews/V1_2.php index 7ec195cc..205fa732 100644 --- a/lib/REST/NextcloudNews/V1_2.php +++ b/lib/REST/NextcloudNews/V1_2.php @@ -18,7 +18,6 @@ use JKingWeb\Arsse\REST\Exception; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse as Response; -use Laminas\Diactoros\Response\EmptyResponse; class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { public const VERSION = "11.0.5"; @@ -86,19 +85,19 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { if ($req->getAttribute("authenticated", false)) { Arsse::$user->id = $req->getAttribute("authenticatedUser"); } else { - return new EmptyResponse(401); + return HTTP::respEmpty(401); } // normalize the input $data = (string) $req->getBody(); if ($data) { // if the entity body is not JSON according to content type, return "415 Unsupported Media Type" if (!HTTP::matchType($req, "", self::ACCEPTED_TYPE)) { - return new EmptyResponse(415, ['Accept' => self::ACCEPTED_TYPE]); + return HTTP::respEmpty(415, ['Accept' => self::ACCEPTED_TYPE]); } $data = @json_decode($data, true); if (json_last_error() !== \JSON_ERROR_NONE) { // if the body could not be parsed as JSON, return "400 Bad Request" - return new EmptyResponse(400); + return HTTP::respEmpty(400); } } else { $data = []; @@ -117,10 +116,10 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { // @codeCoverageIgnoreStart } catch (Exception $e) { // if there was a REST exception return 400 - return new EmptyResponse(400); + return HTTP::respEmpty(400); } catch (AbstractException $e) { // if there was any other Arsse exception return 500 - return new EmptyResponse(500); + return HTTP::respEmpty(500); } // @codeCoverageIgnoreEnd } @@ -162,11 +161,11 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { return $this->paths[$url][$method]; } else { // otherwise return 405 - return new EmptyResponse(405, ['Allow' => implode(", ", array_keys($this->paths[$url]))]); + return HTTP::respEmpty(405, ['Allow' => implode(", ", array_keys($this->paths[$url]))]); } } else { // if the path is not supported, return 404 - return new EmptyResponse(404); + return HTTP::respEmpty(404); } } @@ -268,13 +267,13 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { if (in_array("GET", $allowed)) { array_unshift($allowed, "HEAD"); } - return new EmptyResponse(204, [ + return HTTP::respEmpty(204, [ 'Allow' => implode(",", $allowed), 'Accept' => self::ACCEPTED_TYPE, ]); } else { // if the path is not supported, return 404 - return new EmptyResponse(404); + return HTTP::respEmpty(404); } } @@ -294,12 +293,12 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { switch ($e->getCode()) { // folder already exists - case 10236: return new EmptyResponse(409); + case 10236: return HTTP::respEmpty(409); // folder name not acceptable case 10231: - case 10232: return new EmptyResponse(422); + case 10232: return HTTP::respEmpty(422); // other errors related to input - default: return new EmptyResponse(400); // @codeCoverageIgnore + default: return HTTP::respEmpty(400); // @codeCoverageIgnore } } $folder = $this->folderTranslate(Arsse::$db->folderPropertiesGet(Arsse::$user->id, $folder)); @@ -313,9 +312,9 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->folderRemove(Arsse::$user->id, (int) $url[1]); } catch (ExceptionInput $e) { // folder does not exist - return new EmptyResponse(404); + return HTTP::respEmpty(404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // rename a folder (also supports moving nesting folders, but this is not a feature of the API) @@ -325,24 +324,24 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { switch ($e->getCode()) { // folder does not exist - case 10239: return new EmptyResponse(404); + case 10239: return HTTP::respEmpty(404); // folder already exists - case 10236: return new EmptyResponse(409); + case 10236: return HTTP::respEmpty(409); // folder name not acceptable case 10231: - case 10232: return new EmptyResponse(422); + case 10232: return HTTP::respEmpty(422); // other errors related to input - default: return new EmptyResponse(400); // @codeCoverageIgnore + default: return HTTP::respEmpty(400); // @codeCoverageIgnore } } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // mark all articles associated with a folder as read protected function folderMarkRead(array $url, array $data): ResponseInterface { if (!ValueInfo::id($data['newestItemId'])) { // if the item ID is invalid (i.e. not a positive integer), this is an error - return new EmptyResponse(422); + return HTTP::respEmpty(422); } // build the context $c = (new Context)->hidden(false); @@ -353,15 +352,15 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c); } catch (ExceptionInput $e) { // folder does not exist - return new EmptyResponse(404); + return HTTP::respEmpty(404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // return list of feeds which should be refreshed protected function feedListStale(array $url, array $data): ResponseInterface { if (!$this->isAdmin()) { - return new EmptyResponse(403); + return HTTP::respEmpty(403); } // list stale feeds which should be checked for updates $feeds = Arsse::$db->feedListStale(); @@ -376,21 +375,21 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { // refresh a feed protected function feedUpdate(array $url, array $data): ResponseInterface { if (!$this->isAdmin()) { - return new EmptyResponse(403); + return HTTP::respEmpty(403); } try { Arsse::$db->feedUpdate($data['feedId']); } catch (ExceptionInput $e) { switch ($e->getCode()) { case 10239: // feed does not exist - return new EmptyResponse(404); + return HTTP::respEmpty(404); case 10237: // feed ID invalid - return new EmptyResponse(422); + return HTTP::respEmpty(422); default: // other errors related to input - return new EmptyResponse(400); // @codeCoverageIgnore + return HTTP::respEmpty(400); // @codeCoverageIgnore } } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // add a new feed @@ -401,10 +400,10 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { $id = Arsse::$db->subscriptionAdd(Arsse::$user->id, (string) $data['url']); } catch (ExceptionInput $e) { // feed already exists - return new EmptyResponse(409); + return HTTP::respEmpty(409); } catch (FeedException $e) { // feed could not be retrieved - return new EmptyResponse(422); + return HTTP::respEmpty(422); } // if a folder was specified, move the feed to the correct folder; silently ignore errors if ($data['folderId']) { @@ -447,9 +446,9 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->subscriptionRemove(Arsse::$user->id, (int) $url[1]); } catch (ExceptionInput $e) { // feed does not exist - return new EmptyResponse(404); + return HTTP::respEmpty(404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // rename a feed @@ -459,22 +458,22 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { switch ($e->getCode()) { // subscription does not exist - case 10239: return new EmptyResponse(404); + case 10239: return HTTP::respEmpty(404); // name is invalid case 10231: - case 10232: return new EmptyResponse(422); + case 10232: return HTTP::respEmpty(422); // other errors related to input - default: return new EmptyResponse(400); // @codeCoverageIgnore + default: return HTTP::respEmpty(400); // @codeCoverageIgnore } } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // move a feed to a folder protected function subscriptionMove(array $url, array $data): ResponseInterface { // if no folder is specified this is an error if (!isset($data['folderId'])) { - return new EmptyResponse(422); + return HTTP::respEmpty(422); } // perform the move try { @@ -482,22 +481,22 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { switch ($e->getCode()) { case 10239: // subscription does not exist - return new EmptyResponse(404); + return HTTP::respEmpty(404); case 10235: // folder does not exist case 10237: // folder ID is invalid - return new EmptyResponse(422); + return HTTP::respEmpty(422); default: // other errors related to input - return new EmptyResponse(400); // @codeCoverageIgnore + return HTTP::respEmpty(400); // @codeCoverageIgnore } } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // mark all articles associated with a subscription as read protected function subscriptionMarkRead(array $url, array $data): ResponseInterface { if (!ValueInfo::id($data['newestItemId'])) { // if the item ID is invalid (i.e. not a positive integer), this is an error - return new EmptyResponse(422); + return HTTP::respEmpty(422); } // build the context $c = (new Context)->hidden(false); @@ -508,9 +507,9 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c); } catch (ExceptionInput $e) { // subscription does not exist - return new EmptyResponse(404); + return HTTP::respEmpty(404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // list articles and their properties @@ -579,7 +578,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { ], [$reverse ? "edition desc" : "edition"]); } catch (ExceptionInput $e) { // ID of subscription or folder is not valid - return new EmptyResponse(422); + return HTTP::respEmpty(422); } $out = []; foreach ($items as $item) { @@ -593,14 +592,14 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { protected function articleMarkReadAll(array $url, array $data): ResponseInterface { if (!ValueInfo::id($data['newestItemId'])) { // if the item ID is invalid (i.e. not a positive integer), this is an error - return new EmptyResponse(422); + return HTTP::respEmpty(422); } // build the context $c = (new Context)->hidden(false); $c->editionRange(null, (int) $data['newestItemId']); // perform the operation Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c); - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // mark a single article as read @@ -614,9 +613,9 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->articleMark(Arsse::$user->id, ['read' => $set], $c); } catch (ExceptionInput $e) { // ID is not valid - return new EmptyResponse(404); + return HTTP::respEmpty(404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // mark a single article as read @@ -630,9 +629,9 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->articleMark(Arsse::$user->id, ['starred' => $set], $c); } catch (ExceptionInput $e) { // ID is not valid - return new EmptyResponse(404); + return HTTP::respEmpty(404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // mark an array of articles as read @@ -646,7 +645,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->articleMark(Arsse::$user->id, ['read' => $set], $c); } catch (ExceptionInput $e) { } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // mark an array of articles as starred @@ -660,7 +659,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->articleMark(Arsse::$user->id, ['starred' => $set], $c); } catch (ExceptionInput $e) { } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function userStatus(array $url, array $data): ResponseInterface { @@ -674,18 +673,18 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { protected function cleanupBefore(array $url, array $data): ResponseInterface { if (!$this->isAdmin()) { - return new EmptyResponse(403); + return HTTP::respEmpty(403); } Service::cleanupPre(); - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function cleanupAfter(array $url, array $data): ResponseInterface { if (!$this->isAdmin()) { - return new EmptyResponse(403); + return HTTP::respEmpty(403); } Service::cleanupPost(); - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // return the server version diff --git a/lib/REST/NextcloudNews/Versions.php b/lib/REST/NextcloudNews/Versions.php index 95ee0bf3..503fef14 100644 --- a/lib/REST/NextcloudNews/Versions.php +++ b/lib/REST/NextcloudNews/Versions.php @@ -6,10 +6,10 @@ declare(strict_types=1); namespace JKingWeb\Arsse\REST\NextcloudNews; +use JKingWeb\Arsse\Misc\HTTP; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse as Response; -use Laminas\Diactoros\Response\EmptyResponse; class Versions implements \JKingWeb\Arsse\REST\Handler { public function __construct() { @@ -18,12 +18,12 @@ class Versions implements \JKingWeb\Arsse\REST\Handler { public function dispatch(ServerRequestInterface $req): ResponseInterface { if (!preg_match("<^/?$>D", $req->getRequestTarget())) { // if the request path is more than an empty string or a slash, the client is probably trying a version we don't support - return new EmptyResponse(404); + return HTTP::respEmpty(404); } switch ($req->getMethod()) { case "OPTIONS": // if the request method is OPTIONS, respond accordingly - return new EmptyResponse(204, ['Allow' => "HEAD,GET"]); + return HTTP::respEmpty(204, ['Allow' => "HEAD,GET"]); case "GET": // otherwise return the supported versions $out = [ @@ -34,7 +34,7 @@ class Versions implements \JKingWeb\Arsse\REST\Handler { return new Response($out); default: // if any other method was used, this is an error - return new EmptyResponse(405, ['Allow' => "HEAD,GET"]); + return HTTP::respEmpty(405, ['Allow' => "HEAD,GET"]); } } } diff --git a/lib/REST/TinyTinyRSS/API.php b/lib/REST/TinyTinyRSS/API.php index e167fa4b..d8fb5cac 100644 --- a/lib/REST/TinyTinyRSS/API.php +++ b/lib/REST/TinyTinyRSS/API.php @@ -12,6 +12,7 @@ use JKingWeb\Arsse\Service; use JKingWeb\Arsse\Database; use JKingWeb\Arsse\Context\Context; use JKingWeb\Arsse\Misc\Date; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Misc\ValueInfo as V; use JKingWeb\Arsse\AbstractException; use JKingWeb\Arsse\ExceptionType; @@ -21,7 +22,6 @@ use JKingWeb\Arsse\Feed\Exception as FeedException; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse as Response; -use Laminas\Diactoros\Response\EmptyResponse; class API extends \JKingWeb\Arsse\REST\AbstractHandler { public const LEVEL = 15; // emulated API level @@ -96,11 +96,11 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { public function dispatch(ServerRequestInterface $req): ResponseInterface { if (!preg_match("<^(?:/(?:index\.php)?)?$>D", $req->getRequestTarget())) { // reject paths other than the index - return new EmptyResponse(404); + return HTTP::respEmpty(404); } if ($req->getMethod() === "OPTIONS") { // respond to OPTIONS rquests; the response is a fib, as we technically accept any type or method - return new EmptyResponse(204, [ + return HTTP::respEmpty(204, [ 'Allow' => "POST", 'Accept' => implode(", ", self::ACCEPTED_TYPES), ]); @@ -125,7 +125,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$user->id = $req->getAttribute("authenticatedUser"); } elseif (Arsse::$conf->userHTTPAuthRequired || Arsse::$conf->userPreAuth || $req->getAttribute("authenticationFailed", false)) { // otherwise if HTTP authentication failed or is required, deny access at the HTTP level - return new EmptyResponse(401); + return HTTP::respEmpty(401); } if (strtolower((string) $data['op']) !== "login") { // unless logging in, a session identifier is required @@ -148,7 +148,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { 'content' => $e->getData(), ]); } catch (AbstractException $e) { - return new EmptyResponse(500); + return HTTP::respEmpty(500); } } else { // absence of a request body indicates an error diff --git a/lib/REST/TinyTinyRSS/Icon.php b/lib/REST/TinyTinyRSS/Icon.php index dd718bcb..37f2ce89 100644 --- a/lib/REST/TinyTinyRSS/Icon.php +++ b/lib/REST/TinyTinyRSS/Icon.php @@ -7,10 +7,10 @@ declare(strict_types=1); namespace JKingWeb\Arsse\REST\TinyTinyRSS; use JKingWeb\Arsse\Arsse; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Db\ExceptionInput; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\EmptyResponse as Response; class Icon extends \JKingWeb\Arsse\REST\AbstractHandler { public function __construct() { @@ -22,25 +22,25 @@ class Icon extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$user->id = $req->getAttribute("authenticatedUser"); } elseif ($req->getAttribute("authenticationFailed", false) || Arsse::$conf->userHTTPAuthRequired) { // otherwise if HTTP authentication failed or did not occur when it is required, deny access at the HTTP level - return new Response(401); + return HTTP::respEmpty(401); } if ($req->getMethod() !== "GET") { // only GET requests are allowed - return new Response(405, ['Allow' => "GET"]); + return HTTP::respEmpty(405, ['Allow' => "GET"]); } elseif (!preg_match("<^(\d+)\.ico$>D", $req->getRequestTarget(), $match) || !((int) $match[1])) { - return new Response(404); + return HTTP::respEmpty(404); } try { $url = Arsse::$db->subscriptionIcon(Arsse::$user->id ?? null, (int) $match[1], false)['url'] ?? null; if (!$url) { - return new Response(404); + return HTTP::respEmpty(404); } if (($pos = strpos($url, "\r")) !== false || ($pos = strpos($url, "\n")) !== false) { $url = substr($url, 0, $pos); } - return new Response(301, ['Location' => $url]); + return HTTP::respEmpty(301, ['Location' => $url]); } catch (ExceptionInput $e) { - return new Response(404); + return HTTP::respEmpty(404); } } } diff --git a/tests/cases/REST/Fever/TestAPI.php b/tests/cases/REST/Fever/TestAPI.php index 6a618b68..59d1858c 100644 --- a/tests/cases/REST/Fever/TestAPI.php +++ b/tests/cases/REST/Fever/TestAPI.php @@ -9,6 +9,7 @@ namespace JKingWeb\Arsse\TestCase\REST\Fever; use JKingWeb\Arsse\Arsse; use JKingWeb\Arsse\User; use JKingWeb\Arsse\Database; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Test\Result; use JKingWeb\Arsse\Context\Context; use JKingWeb\Arsse\Db\ExceptionInput; @@ -17,7 +18,6 @@ use JKingWeb\Arsse\REST\Fever\API; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse; use Laminas\Diactoros\Response\XmlResponse; -use Laminas\Diactoros\Response\EmptyResponse; /** @covers \JKingWeb\Arsse\REST\Fever\API */ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { @@ -194,7 +194,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { public function provideTokenAuthenticationRequests(): iterable { $success = new JsonResponse(['auth' => 1]); $failure = new JsonResponse(['auth' => 0]); - $denied = new EmptyResponse(401); + $denied = HTTP::respEmpty(401); return [ [false, true, null, [], ['api' => null], $failure], [false, false, null, [], ['api' => null], $failure], @@ -421,8 +421,8 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { public function provideInvalidRequests(): iterable { return [ - 'Not an API request' => ["", "", "POST", null, new EmptyResponse(404)], - 'Wrong method' => ["api", "", "PUT", null, new EmptyResponse(405, ['Allow' => "OPTIONS,POST"])], + 'Not an API request' => ["", "", "POST", null, HTTP::respEmpty(404)], + 'Wrong method' => ["api", "", "PUT", null, HTTP::respEmpty(405, ['Allow' => "OPTIONS,POST"])], 'Non-standard method' => ["api", "", "GET", null, new JsonResponse([])], 'Wrong content type' => ["api", '{"api_key":"validToken"}', "POST", "application/json", new JsonResponse([])], // some clients send nonsensical content types; Fever seems to have allowed this 'Non-standard content type' => ["api", '{"api_key":"validToken"}', "POST", "multipart/form-data; boundary=33b68964f0de4c1f-5144aa6caaa6e4a8-18bfaf416a1786c8-5c5053a45f221bc1", new JsonResponse([])], // some clients send nonsensical content types; Fever seems to have allowed this @@ -494,7 +494,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { } public function testAnswerOptionsRequest(): void { - $exp = new EmptyResponse(204, [ + $exp = HTTP::respEmpty(204, [ 'Allow' => "POST", 'Accept' => "application/x-www-form-urlencoded, multipart/form-data", ]); diff --git a/tests/cases/REST/Miniflux/TestStatus.php b/tests/cases/REST/Miniflux/TestStatus.php index bcf81d18..cf573e3e 100644 --- a/tests/cases/REST/Miniflux/TestStatus.php +++ b/tests/cases/REST/Miniflux/TestStatus.php @@ -6,10 +6,10 @@ declare(strict_types=1); namespace JKingWeb\Arsse\TestCase\REST\Miniflux; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\REST\Miniflux\Status; use JKingWeb\Arsse\REST\Miniflux\V1; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\EmptyResponse; use Laminas\Diactoros\Response\TextResponse; /** @covers \JKingWeb\Arsse\REST\Miniflux\Status */ @@ -23,12 +23,12 @@ class TestStatus extends \JKingWeb\Arsse\Test\AbstractTest { public function provideRequests(): iterable { return [ ["/version", "GET", new TextResponse(V1::VERSION)], - ["/version", "POST", new EmptyResponse(405, ['Allow' => "HEAD, GET"])], - ["/version", "OPTIONS", new EmptyResponse(204, ['Allow' => "HEAD, GET"])], + ["/version", "POST", HTTP::respEmpty(405, ['Allow' => "HEAD, GET"])], + ["/version", "OPTIONS", HTTP::respEmpty(204, ['Allow' => "HEAD, GET"])], ["/healthcheck", "GET", new TextResponse("OK")], - ["/healthcheck", "POST", new EmptyResponse(405, ['Allow' => "HEAD, GET"])], - ["/healthcheck", "OPTIONS", new EmptyResponse(204, ['Allow' => "HEAD, GET"])], - ["/version/", "GET", new EmptyResponse(404)], + ["/healthcheck", "POST", HTTP::respEmpty(405, ['Allow' => "HEAD, GET"])], + ["/healthcheck", "OPTIONS", HTTP::respEmpty(204, ['Allow' => "HEAD, GET"])], + ["/version/", "GET", HTTP::respEmpty(404)], ]; } } diff --git a/tests/cases/REST/Miniflux/TestV1.php b/tests/cases/REST/Miniflux/TestV1.php index 9623fd3d..89610474 100644 --- a/tests/cases/REST/Miniflux/TestV1.php +++ b/tests/cases/REST/Miniflux/TestV1.php @@ -14,6 +14,7 @@ use JKingWeb\Arsse\Context\RootContext; use JKingWeb\Arsse\Context\UnionContext; use JKingWeb\Arsse\User; use JKingWeb\Arsse\Database; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Db\Transaction; use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\REST\Miniflux\V1; @@ -26,7 +27,6 @@ use JKingWeb\Arsse\User\ExceptionInput as UserExceptionInput; use JKingWeb\Arsse\Test\Result; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse as Response; -use Laminas\Diactoros\Response\EmptyResponse; use Laminas\Diactoros\Response\TextResponse; /** @covers \JKingWeb\Arsse\REST\Miniflux\V1 */ @@ -102,7 +102,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { /** @dataProvider provideAuthResponses */ public function testAuthenticateAUser($token, bool $auth, bool $success): void { - $exp = $success ? new EmptyResponse(404) : new ErrorResponse("401", 401); + $exp = $success ? HTTP::respEmpty(404) : new ErrorResponse("401", 401); $user = "john.doe@example.com"; if ($token !== null) { $headers = ['X-Auth-Token' => $token]; @@ -133,7 +133,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { /** @dataProvider provideInvalidPaths */ public function testRespondToInvalidPaths($path, $method, $code, $allow = null): void { - $exp = new EmptyResponse($code, $allow ? ['Allow' => $allow] : []); + $exp = HTTP::respEmpty($code, $allow ? ['Allow' => $allow] : []); $this->assertMessage($exp, $this->req($method, $path)); } @@ -148,7 +148,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { /** @dataProvider provideOptionsRequests */ public function testRespondToOptionsRequests(string $url, string $allow, string $accept): void { - $exp = new EmptyResponse(204, [ + $exp = HTTP::respEmpty(204, [ 'Allow' => $allow, 'Accept' => $accept, ]); @@ -382,7 +382,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { Arsse::$user->method("remove")->willReturn(true); Arsse::$user->expects($this->exactly(1))->method("lookup")->with(2112); Arsse::$user->expects($this->exactly(1))->method("remove")->with("john.doe@example.com"); - $this->assertMessage(new EmptyResponse(204), $this->req("DELETE", "/users/2112")); + $this->assertMessage(HTTP::respEmpty(204), $this->req("DELETE", "/users/2112")); } public function testDeleteAMissingUser(): void { @@ -484,7 +484,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function testDeleteARealCategory(): void { $this->dbMock->folderRemove->returns(true)->throws(new ExceptionInput("subjectMissing")); - $this->assertMessage(new EmptyResponse(204), $this->req("DELETE", "/categories/2112")); + $this->assertMessage(HTTP::respEmpty(204), $this->req("DELETE", "/categories/2112")); $this->dbMock->folderRemove->calledWith("john.doe@example.com", 2111); $this->assertMessage(new ErrorResponse("404", 404), $this->req("DELETE", "/categories/47")); $this->dbMock->folderRemove->calledWith("john.doe@example.com", 46); @@ -497,7 +497,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { ['id' => 2112], ]))); $this->dbMock->subscriptionRemove->returns(true); - $this->assertMessage(new EmptyResponse(204), $this->req("DELETE", "/categories/1")); + $this->assertMessage(HTTP::respEmpty(204), $this->req("DELETE", "/categories/1")); Phony::inOrder( $this->dbMock->begin->calledWith(), $this->dbMock->subscriptionList->calledWith("john.doe@example.com", null, false), @@ -680,7 +680,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function testDeleteAFeed(): void { $this->dbMock->subscriptionRemove->returns(true); - $this->assertMessage(new EmptyResponse(204), $this->req("DELETE", "/feeds/2112")); + $this->assertMessage(HTTP::respEmpty(204), $this->req("DELETE", "/feeds/2112")); $this->dbMock->subscriptionRemove->calledWith(Arsse::$user->id, 2112); } @@ -864,9 +864,9 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { [['entry_ids' => [1], 'status' => 1], null, new ErrorResponse(["InvalidInputType", 'field' => "status", 'expected' => "string", 'actual' => "integer"], 422)], [['entry_ids' => [0], 'status' => "read"], null, new ErrorResponse(["InvalidInputValue", 'field' => "entry_ids"], 422)], [['entry_ids' => [1], 'status' => "reread"], null, new ErrorResponse(["InvalidInputValue", 'field' => "status"], 422)], - [['entry_ids' => [1, 2], 'status' => "read"], ['read' => true, 'hidden' => false], new EmptyResponse(204)], - [['entry_ids' => [1, 2], 'status' => "unread"], ['read' => false, 'hidden' => false], new EmptyResponse(204)], - [['entry_ids' => [1, 2], 'status' => "removed"], ['read' => true, 'hidden' => true], new EmptyResponse(204)], + [['entry_ids' => [1, 2], 'status' => "read"], ['read' => true, 'hidden' => false], HTTP::respEmpty(204)], + [['entry_ids' => [1, 2], 'status' => "unread"], ['read' => false, 'hidden' => false], HTTP::respEmpty(204)], + [['entry_ids' => [1, 2], 'status' => "removed"], ['read' => true, 'hidden' => true], HTTP::respEmpty(204)], ]; } @@ -889,13 +889,13 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { self::clearData(); $c = (new Context)->hidden(false); return [ - ["/users/42/mark-all-as-read", $c, 1123, new EmptyResponse(204)], + ["/users/42/mark-all-as-read", $c, 1123, HTTP::respEmpty(204)], ["/users/2112/mark-all-as-read", $c, null, new ErrorResponse("403", 403)], - ["/feeds/47/mark-all-as-read", (clone $c)->subscription(47), 2112, new EmptyResponse(204)], + ["/feeds/47/mark-all-as-read", (clone $c)->subscription(47), 2112, HTTP::respEmpty(204)], ["/feeds/2112/mark-all-as-read", (clone $c)->subscription(2112), new ExceptionInput("idMissing"), new ErrorResponse("404", 404)], - ["/categories/47/mark-all-as-read", (clone $c)->folder(46), 1337, new EmptyResponse(204)], + ["/categories/47/mark-all-as-read", (clone $c)->folder(46), 1337, HTTP::respEmpty(204)], ["/categories/2112/mark-all-as-read", (clone $c)->folder(2111), new ExceptionInput("idMissing"), new ErrorResponse("404", 404)], - ["/categories/1/mark-all-as-read", (clone $c)->folderShallow(0), 6666, new EmptyResponse(204)], + ["/categories/1/mark-all-as-read", (clone $c)->folderShallow(0), 6666, HTTP::respEmpty(204)], ]; } @@ -929,15 +929,15 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideBookmarkTogglings(): iterable { self::clearData(); return [ - [1, true, new EmptyResponse(204)], - [0, false, new EmptyResponse(204)], + [1, true, HTTP::respEmpty(204)], + [0, false, HTTP::respEmpty(204)], [new ExceptionInput("subjectMissing"), null, new ErrorResponse("404", 404)], ]; } public function testRefreshAFeed(): void { $this->dbMock->subscriptionPropertiesGet->returns([]); - $this->assertMessage(new EmptyResponse(204), $this->req("PUT", "/feeds/47/refresh")); + $this->assertMessage(HTTP::respEmpty(204), $this->req("PUT", "/feeds/47/refresh")); $this->dbMock->subscriptionPropertiesGet->calledWith(Arsse::$user->id, 47); } @@ -948,7 +948,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { } public function testRefreshAllFeeds(): void { - $this->assertMessage(new EmptyResponse(204), $this->req("PUT", "/feeds/refresh")); + $this->assertMessage(HTTP::respEmpty(204), $this->req("PUT", "/feeds/refresh")); } /** @dataProvider provideImports */ diff --git a/tests/cases/REST/NextcloudNews/TestV1_2.php b/tests/cases/REST/NextcloudNews/TestV1_2.php index f58f87d6..08f1f709 100644 --- a/tests/cases/REST/NextcloudNews/TestV1_2.php +++ b/tests/cases/REST/NextcloudNews/TestV1_2.php @@ -11,13 +11,13 @@ use JKingWeb\Arsse\User; use JKingWeb\Arsse\Database; use JKingWeb\Arsse\Test\Result; use JKingWeb\Arsse\Misc\Date; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Context\Context; use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\Db\Transaction; use JKingWeb\Arsse\REST\NextcloudNews\V1_2; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse as Response; -use Laminas\Diactoros\Response\EmptyResponse; /** @covers \JKingWeb\Arsse\REST\NextcloudNews\V1_2 */ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { @@ -336,13 +336,13 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { } public function testSendAuthenticationChallenge(): void { - $exp = new EmptyResponse(401); + $exp = HTTP::respEmpty(401); $this->assertMessage($exp, $this->req("GET", "/", "", [], false)); } /** @dataProvider provideInvalidPaths */ public function testRespondToInvalidPaths($path, $method, $code, $allow = null): void { - $exp = new EmptyResponse($code, $allow ? ['Allow' => $allow] : []); + $exp = HTTP::respEmpty($code, $allow ? ['Allow' => $allow] : []); $this->assertMessage($exp, $this->req($method, $path)); } @@ -374,16 +374,16 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { } public function testRespondToInvalidInputTypes(): void { - $exp = new EmptyResponse(415, ['Accept' => "application/json"]); + $exp = HTTP::respEmpty(415, ['Accept' => "application/json"]); $this->assertMessage($exp, $this->req("PUT", "/folders/1", '', ['Content-Type' => "application/xml"])); - $exp = new EmptyResponse(400); + $exp = HTTP::respEmpty(400); $this->assertMessage($exp, $this->req("PUT", "/folders/1", '')); $this->assertMessage($exp, $this->req("PUT", "/folders/1", '', ['Content-Type' => null])); } /** @dataProvider provideOptionsRequests */ public function testRespondToOptionsRequests(string $url, string $allow, string $accept): void { - $exp = new EmptyResponse(204, [ + $exp = HTTP::respEmpty(204, [ 'Allow' => $allow, 'Accept' => $accept, ]); @@ -436,19 +436,19 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { [['name' => "Software"], false, 1, new Response(['folders' => [['id' => 1, 'name' => "Software"]]])], [['name' => "Hardware"], true, "2", new Response(['folders' => [['id' => 2, 'name' => "Hardware"]]])], [['name' => "Hardware"], false, "2", new Response(['folders' => [['id' => 2, 'name' => "Hardware"]]])], - [['name' => "Software"], true, new ExceptionInput("constraintViolation"), new EmptyResponse(409)], - [['name' => ""], true, new ExceptionInput("whitespace"), new EmptyResponse(422)], - [['name' => " "], true, new ExceptionInput("whitespace"), new EmptyResponse(422)], - [['name' => null], true, new ExceptionInput("missing"), new EmptyResponse(422)], + [['name' => "Software"], true, new ExceptionInput("constraintViolation"), HTTP::respEmpty(409)], + [['name' => ""], true, new ExceptionInput("whitespace"), HTTP::respEmpty(422)], + [['name' => " "], true, new ExceptionInput("whitespace"), HTTP::respEmpty(422)], + [['name' => null], true, new ExceptionInput("missing"), HTTP::respEmpty(422)], ]; } public function testRemoveAFolder(): void { $this->dbMock->folderRemove->with($this->userId, 1)->returns(true)->throws(new ExceptionInput("subjectMissing")); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("DELETE", "/folders/1")); // fail on the second invocation because it no longer exists - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("DELETE", "/folders/1")); $this->dbMock->folderRemove->times(2)->calledWith($this->userId, 1); } @@ -467,12 +467,12 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideFolderRenamings(): array { return [ - [['name' => "Software"], 1, true, new EmptyResponse(204)], - [['name' => "Software"], 2, new ExceptionInput("constraintViolation"), new EmptyResponse(409)], - [['name' => "Software"], 3, new ExceptionInput("subjectMissing"), new EmptyResponse(404)], - [['name' => ""], 2, new ExceptionInput("whitespace"), new EmptyResponse(422)], - [['name' => " "], 2, new ExceptionInput("whitespace"), new EmptyResponse(422)], - [['name' => null], 2, new ExceptionInput("missing"), new EmptyResponse(422)], + [['name' => "Software"], 1, true, HTTP::respEmpty(204)], + [['name' => "Software"], 2, new ExceptionInput("constraintViolation"), HTTP::respEmpty(409)], + [['name' => "Software"], 3, new ExceptionInput("subjectMissing"), HTTP::respEmpty(404)], + [['name' => ""], 2, new ExceptionInput("whitespace"), HTTP::respEmpty(422)], + [['name' => " "], 2, new ExceptionInput("whitespace"), HTTP::respEmpty(422)], + [['name' => null], 2, new ExceptionInput("missing"), HTTP::respEmpty(422)], ]; } @@ -540,19 +540,19 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { return [ [['url' => "http://example.com/news.atom", 'folderId' => 3], 2112, 0, $this->feeds['db'][0], new ExceptionInput("idMissing"), new Response(['feeds' => [$this->feeds['rest'][0]]])], [['url' => "http://example.org/news.atom", 'folderId' => 8], 42, 4758915, $this->feeds['db'][1], true, new Response(['feeds' => [$this->feeds['rest'][1]], 'newestItemId' => 4758915])], - [['url' => "http://example.com/news.atom", 'folderId' => 3], new ExceptionInput("constraintViolation"), 0, $this->feeds['db'][0], new ExceptionInput("idMissing"), new EmptyResponse(409)], - [['url' => "http://example.org/news.atom", 'folderId' => 8], new ExceptionInput("constraintViolation"), 4758915, $this->feeds['db'][1], true, new EmptyResponse(409)], - [[], $feedException, 0, [], false, new EmptyResponse(422)], + [['url' => "http://example.com/news.atom", 'folderId' => 3], new ExceptionInput("constraintViolation"), 0, $this->feeds['db'][0], new ExceptionInput("idMissing"), HTTP::respEmpty(409)], + [['url' => "http://example.org/news.atom", 'folderId' => 8], new ExceptionInput("constraintViolation"), 4758915, $this->feeds['db'][1], true, HTTP::respEmpty(409)], + [[], $feedException, 0, [], false, HTTP::respEmpty(422)], [['url' => "http://example.net/news.atom", 'folderId' => -1], 47, 2112, $this->feeds['db'][2], new ExceptionInput("typeViolation"), new Response(['feeds' => [$this->feeds['rest'][2]], 'newestItemId' => 2112])], ]; } public function testRemoveASubscription(): void { $this->dbMock->subscriptionRemove->with($this->userId, 1)->returns(true)->throws(new ExceptionInput("subjectMissing")); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("DELETE", "/feeds/1")); // fail on the second invocation because it no longer exists - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("DELETE", "/feeds/1")); $this->dbMock->subscriptionRemove->times(2)->calledWith($this->userId, 1); } @@ -571,17 +571,17 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->subscriptionPropertiesSet->with($this->userId, 1, ['folder' => 2112])->throws(new ExceptionInput("idMissing")); // folder does not exist $this->dbMock->subscriptionPropertiesSet->with($this->userId, 1, ['folder' => -1])->throws(new ExceptionInput("typeViolation")); // folder is invalid $this->dbMock->subscriptionPropertiesSet->with($this->userId, 42, $this->anything())->throws(new ExceptionInput("subjectMissing")); // subscription does not exist - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/move", json_encode($in[0]))); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/move", json_encode($in[1]))); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/move", json_encode($in[2]))); - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("PUT", "/feeds/42/move", json_encode($in[3]))); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/move", json_encode($in[4]))); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/move", json_encode($in[5]))); } @@ -601,17 +601,17 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->subscriptionPropertiesSet->with($this->userId, 1, $this->identicalTo(['title' => ""]))->throws(new ExceptionInput("missing")); $this->dbMock->subscriptionPropertiesSet->with($this->userId, 1, $this->identicalTo(['title' => false]))->throws(new ExceptionInput("missing")); $this->dbMock->subscriptionPropertiesSet->with($this->userId, 42, $this->anything())->throws(new ExceptionInput("subjectMissing")); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/rename", json_encode($in[0]))); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/rename", json_encode($in[1]))); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/rename", json_encode($in[2]))); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/rename", json_encode($in[3]))); - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("PUT", "/feeds/42/rename", json_encode($in[4]))); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/rename", json_encode($in[6]))); } @@ -633,7 +633,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { public function testListStaleFeedsWithoutAuthority(): void { $this->userMock->propertiesGet->returns(['admin' => false]); - $exp = new EmptyResponse(403); + $exp = HTTP::respEmpty(403); $this->assertMessage($exp, $this->req("GET", "/feeds/all")); $this->dbMock->feedListStale->never()->called(); } @@ -649,11 +649,11 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->feedUpdate->with(42)->returns(true); $this->dbMock->feedUpdate->with(2112)->throws(new ExceptionInput("subjectMissing")); $this->dbMock->feedUpdate->with($this->lessThan(1))->throws(new ExceptionInput("typeViolation")); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("GET", "/feeds/update", json_encode($in[0]))); - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("GET", "/feeds/update", json_encode($in[1]))); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("GET", "/feeds/update", json_encode($in[2]))); $this->assertMessage($exp, $this->req("GET", "/feeds/update", json_encode($in[3]))); $this->assertMessage($exp, $this->req("GET", "/feeds/update", json_encode($in[4]))); @@ -661,7 +661,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { public function testUpdateAFeedWithoutAuthority(): void { $this->userMock->propertiesGet->returns(['admin' => false]); - $exp = new EmptyResponse(403); + $exp = HTTP::respEmpty(403); $this->assertMessage($exp, $this->req("GET", "/feeds/update", ['feedId' => 42])); $this->dbMock->feedUpdate->never()->called(); } @@ -684,7 +684,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $t = Date::normalize(time()); $out = new Result($this->v($this->articles['db'])); $r200 = new Response(['items' => $this->articles['rest']]); - $r422 = new EmptyResponse(422); + $r422 = HTTP::respEmpty(422); return [ ["/items", [], clone $c, $out, $r200], ["/items", ['type' => 0, 'id' => 42], (clone $c)->subscription(42), new ExceptionInput("idMissing"), $r422], @@ -720,13 +720,13 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $in = json_encode(['newestItemId' => 2112]); $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->folder(1)->editionRange(null, 2112)->hidden(false)))->returns(42); $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->folder(42)->editionRange(null, 2112)->hidden(false)))->throws(new ExceptionInput("idMissing")); // folder doesn't exist - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/folders/1/read", $in)); $this->assertMessage($exp, $this->req("PUT", "/folders/1/read?newestItemId=2112")); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/folders/1/read")); $this->assertMessage($exp, $this->req("PUT", "/folders/1/read?newestItemId=ook")); - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("PUT", "/folders/42/read", $in)); } @@ -735,13 +735,13 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $in = json_encode(['newestItemId' => 2112]); $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->subscription(1)->editionRange(null, 2112)->hidden(false)))->returns(42); $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->subscription(42)->editionRange(null, 2112)->hidden(false)))->throws(new ExceptionInput("idMissing")); // subscription doesn't exist - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/read", $in)); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/read?newestItemId=2112")); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/read")); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/read?newestItemId=ook")); - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("PUT", "/feeds/42/read", $in)); } @@ -749,10 +749,10 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $read = ['read' => true]; $in = json_encode(['newestItemId' => 2112]); $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->editionRange(null, 2112)))->returns(42); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/items/read", $in)); $this->assertMessage($exp, $this->req("PUT", "/items/read?newestItemId=2112")); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/items/read")); $this->assertMessage($exp, $this->req("PUT", "/items/read?newestItemId=ook")); } @@ -770,12 +770,12 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->articleMark->with($this->userId, $star, $this->equalTo((new Context)->article(2112)))->throws(new ExceptionInput("subjectMissing")); // article doesn't exist doesn't exist $this->dbMock->articleMark->with($this->userId, $unstar, $this->equalTo((new Context)->article(4)))->returns(42); $this->dbMock->articleMark->with($this->userId, $unstar, $this->equalTo((new Context)->article(1337)))->throws(new ExceptionInput("subjectMissing")); // article doesn't exist doesn't exist - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/items/1/read")); $this->assertMessage($exp, $this->req("PUT", "/items/2/unread")); $this->assertMessage($exp, $this->req("PUT", "/items/1/3/star")); $this->assertMessage($exp, $this->req("PUT", "/items/4400/4/unstar")); - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("PUT", "/items/42/read")); $this->assertMessage($exp, $this->req("PUT", "/items/47/unread")); $this->assertMessage($exp, $this->req("PUT", "/items/1/2112/star")); @@ -801,7 +801,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->articleMark->with($this->userId, $this->anything(), $this->anything())->returns(42); $this->dbMock->articleMark->with($this->userId, $this->anything(), $this->equalTo((new Context)->editions([])))->throws(new ExceptionInput("tooShort")); // data model function requires one valid integer for multiples $this->dbMock->articleMark->with($this->userId, $this->anything(), $this->equalTo((new Context)->articles([])))->throws(new ExceptionInput("tooShort")); // data model function requires one valid integer for multiples - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/items/read/multiple")); $this->assertMessage($exp, $this->req("PUT", "/items/unread/multiple")); $this->assertMessage($exp, $this->req("PUT", "/items/star/multiple")); @@ -860,28 +860,28 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { public function testCleanUpBeforeUpdate(): void { $this->dbMock->feedCleanup->with()->returns(true); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("GET", "/cleanup/before-update")); $this->dbMock->feedCleanup->calledWith(); } public function testCleanUpBeforeUpdateWithoutAuthority(): void { $this->userMock->propertiesGet->returns(['admin' => false]); - $exp = new EmptyResponse(403); + $exp = HTTP::respEmpty(403); $this->assertMessage($exp, $this->req("GET", "/cleanup/before-update")); $this->dbMock->feedCleanup->never()->called(); } public function testCleanUpAfterUpdate(): void { $this->dbMock->articleCleanup->with()->returns(true); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("GET", "/cleanup/after-update")); $this->dbMock->articleCleanup->calledWith(); } public function testCleanUpAfterUpdateWithoutAuthority(): void { $this->userMock->propertiesGet->returns(['admin' => false]); - $exp = new EmptyResponse(403); + $exp = HTTP::respEmpty(403); $this->assertMessage($exp, $this->req("GET", "/cleanup/after-update")); $this->dbMock->feedCleanup->never()->called(); } diff --git a/tests/cases/REST/NextcloudNews/TestVersions.php b/tests/cases/REST/NextcloudNews/TestVersions.php index b5d5679d..a254772b 100644 --- a/tests/cases/REST/NextcloudNews/TestVersions.php +++ b/tests/cases/REST/NextcloudNews/TestVersions.php @@ -6,10 +6,10 @@ declare(strict_types=1); namespace JKingWeb\Arsse\TestCase\REST\NextcloudNews; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\REST\NextcloudNews\Versions; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse as Response; -use Laminas\Diactoros\Response\EmptyResponse; /** @covers \JKingWeb\Arsse\REST\NextcloudNews\Versions */ class TestVersions extends \JKingWeb\Arsse\Test\AbstractTest { @@ -32,17 +32,17 @@ class TestVersions extends \JKingWeb\Arsse\Test\AbstractTest { } public function testRespondToOptionsRequest(): void { - $exp = new EmptyResponse(204, ['Allow' => "HEAD,GET"]); + $exp = HTTP::respEmpty(204, ['Allow' => "HEAD,GET"]); $this->assertMessage($exp, $this->req("OPTIONS", "/")); } public function testUseIncorrectMethod(): void { - $exp = new EmptyResponse(405, ['Allow' => "HEAD,GET"]); + $exp = HTTP::respEmpty(405, ['Allow' => "HEAD,GET"]); $this->assertMessage($exp, $this->req("POST", "/")); } public function testUseIncorrectPath(): void { - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("GET", "/ook")); $this->assertMessage($exp, $this->req("OPTIONS", "/ook")); } diff --git a/tests/cases/REST/TestREST.php b/tests/cases/REST/TestREST.php index 0ba6eada..059803da 100644 --- a/tests/cases/REST/TestREST.php +++ b/tests/cases/REST/TestREST.php @@ -12,13 +12,13 @@ use JKingWeb\Arsse\REST; use JKingWeb\Arsse\REST\Exception501; use JKingWeb\Arsse\REST\NextcloudNews\V1_2 as NCN; use JKingWeb\Arsse\REST\TinyTinyRSS\API as TTRSS; +use JKingWeb\Arsse\Misc\HTTP; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Request; use Laminas\Diactoros\Response; use Laminas\Diactoros\ServerRequest; use Laminas\Diactoros\Response\TextResponse; -use Laminas\Diactoros\Response\EmptyResponse; /** @covers \JKingWeb\Arsse\REST */ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { @@ -96,7 +96,7 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { public function testSendAuthenticationChallenges(): void { self::setConf(); $r = new REST(); - $in = new EmptyResponse(401); + $in = HTTP::respEmpty(401); $exp = $in->withHeader("WWW-Authenticate", 'Basic realm="OOK", charset="UTF-8"'); $act = $r->challenge($in, "OOK"); $this->assertMessage($exp, $act); @@ -190,8 +190,8 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { public function testAddCorsHeaders(string $reqMethod, array $reqHeaders, array $resHeaders, array $expHeaders): void { $r = new REST(); $req = new Request("", $reqMethod, "php://memory", $reqHeaders); - $res = new EmptyResponse(204, $resHeaders); - $exp = new EmptyResponse(204, $expHeaders); + $res = HTTP::respEmpty(204, $resHeaders); + $exp = HTTP::respEmpty(204, $expHeaders); $act = $r->corsApply($res, $req); $this->assertMessage($exp, $act); } @@ -268,21 +268,21 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { $stream = fopen("php://memory", "w+b"); fwrite($stream, "ook"); return [ - [new EmptyResponse(204), new EmptyResponse(204)], - [new EmptyResponse(401), new EmptyResponse(401, ['WWW-Authenticate' => "Fake Value"])], - [new EmptyResponse(204, ['Allow' => "PUT"]), new EmptyResponse(204, ['Allow' => "PUT, OPTIONS"])], - [new EmptyResponse(204, ['Allow' => "PUT, OPTIONS"]), new EmptyResponse(204, ['Allow' => "PUT, OPTIONS"])], - [new EmptyResponse(204, ['Allow' => "PUT,OPTIONS"]), new EmptyResponse(204, ['Allow' => "PUT, OPTIONS"])], - [new EmptyResponse(204, ['Allow' => ["PUT", "OPTIONS"]]), new EmptyResponse(204, ['Allow' => "PUT, OPTIONS"])], - [new EmptyResponse(204, ['Allow' => ["PUT, DELETE", "OPTIONS"]]), new EmptyResponse(204, ['Allow' => "PUT, DELETE, OPTIONS"])], - [new EmptyResponse(204, ['Allow' => "HEAD,GET"]), new EmptyResponse(204, ['Allow' => "HEAD, GET, OPTIONS"])], - [new EmptyResponse(204, ['Allow' => "GET"]), new EmptyResponse(204, ['Allow' => "GET, HEAD, OPTIONS"])], - [new TextResponse("ook", 200), new TextResponse("ook", 200, ['Content-Length' => "3"])], - [new TextResponse("", 200), new TextResponse("", 200, ['Content-Length' => "0"])], - [new TextResponse("ook", 404), new TextResponse("ook", 404, ['Content-Length' => "3"])], - [new TextResponse("", 404), new TextResponse("", 404)], - [new Response($stream, 200), new Response($stream, 200, ['Content-Length' => "3"]), new Request("", "GET")], - [new Response($stream, 200), new EmptyResponse(200, ['Content-Length' => "3"]), new Request("", "HEAD")], + [HTTP::respEmpty(204), HTTP::respEmpty(204)], + [HTTP::respEmpty(401), HTTP::respEmpty(401, ['WWW-Authenticate' => "Fake Value"])], + [HTTP::respEmpty(204, ['Allow' => "PUT"]), HTTP::respEmpty(204, ['Allow' => "PUT, OPTIONS"])], + [HTTP::respEmpty(204, ['Allow' => "PUT, OPTIONS"]), HTTP::respEmpty(204, ['Allow' => "PUT, OPTIONS"])], + [HTTP::respEmpty(204, ['Allow' => "PUT,OPTIONS"]), HTTP::respEmpty(204, ['Allow' => "PUT, OPTIONS"])], + [HTTP::respEmpty(204, ['Allow' => ["PUT", "OPTIONS"]]), HTTP::respEmpty(204, ['Allow' => "PUT, OPTIONS"])], + [HTTP::respEmpty(204, ['Allow' => ["PUT, DELETE", "OPTIONS"]]), HTTP::respEmpty(204, ['Allow' => "PUT, DELETE, OPTIONS"])], + [HTTP::respEmpty(204, ['Allow' => "HEAD,GET"]), HTTP::respEmpty(204, ['Allow' => "HEAD, GET, OPTIONS"])], + [HTTP::respEmpty(204, ['Allow' => "GET"]), HTTP::respEmpty(204, ['Allow' => "GET, HEAD, OPTIONS"])], + [new TextResponse("ook", 200), new TextResponse("ook", 200, ['Content-Length' => "3"])], + [new TextResponse("", 200), new TextResponse("", 200, ['Content-Length' => "0"])], + [new TextResponse("ook", 404), new TextResponse("ook", 404, ['Content-Length' => "3"])], + [new TextResponse("", 404), new TextResponse("", 404)], + [new Response($stream, 200), new Response($stream, 200, ['Content-Length' => "3"]), new Request("", "GET")], + [new Response($stream, 200), HTTP::respEmpty(200, ['Content-Length' => "3"]), new Request("", "HEAD")], ]; } @@ -297,7 +297,7 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { }); if ($called) { $hMock = $this->mock($class); - $hMock->dispatch->returns(new EmptyResponse(204)); + $hMock->dispatch->returns(HTTP::respEmpty(204)); $this->objMock->get->with($class)->returns($hMock); Arsse::$obj = $this->objMock->get(); } diff --git a/tests/cases/REST/TinyTinyRSS/TestAPI.php b/tests/cases/REST/TinyTinyRSS/TestAPI.php index 5220a69f..d643491f 100644 --- a/tests/cases/REST/TinyTinyRSS/TestAPI.php +++ b/tests/cases/REST/TinyTinyRSS/TestAPI.php @@ -11,6 +11,7 @@ use JKingWeb\Arsse\User; use JKingWeb\Arsse\Database; use JKingWeb\Arsse\Test\Result; use JKingWeb\Arsse\Misc\Date; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Context\Context; use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\Db\Transaction; @@ -18,7 +19,6 @@ use JKingWeb\Arsse\REST\TinyTinyRSS\API; use JKingWeb\Arsse\Feed\Exception as FeedException; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse as Response; -use Laminas\Diactoros\Response\EmptyResponse; /** @covers \JKingWeb\Arsse\REST\TinyTinyRSS\API * @covers \JKingWeb\Arsse\REST\TinyTinyRSS\Exception */ @@ -188,12 +188,12 @@ LONG_STRING; $this->assertMessage($exp, $this->req(null, "POST", "", "")); $this->assertMessage($exp, $this->req(null, "POST", "/", "")); $this->assertMessage($exp, $this->req(null, "POST", "/index.php", "")); - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req(null, "POST", "/bad/path", "")); } public function testHandleOptionsRequest(): void { - $exp = new EmptyResponse(204, [ + $exp = HTTP::respEmpty(204, [ 'Allow' => "POST", 'Accept' => "application/json, text/json", ]); @@ -215,7 +215,7 @@ LONG_STRING; $this->userMock->auth->with("jane.doe@example.com", "superman")->returns(true); $this->dbMock->sessionCreate->with("john.doe@example.com")->returns("PriestsOfSyrinx", "SolarFederation"); $this->dbMock->sessionCreate->with("jane.doe@example.com")->returns("ClockworkAngels", "SevenCitiesOfGold"); - if ($sessions instanceof EmptyResponse) { + if ($sessions instanceof ResponseInterface) { $exp1 = $sessions; $exp2 = $sessions; } elseif ($sessions) { @@ -260,7 +260,7 @@ LONG_STRING; 'op' => "isLoggedIn", 'sid' => $data, ]; - if ($result instanceof EmptyResponse) { + if ($result instanceof ResponseInterface) { $exp1 = $result; $exp2 = null; } elseif ($result) { @@ -333,7 +333,7 @@ LONG_STRING; 'userHTTPAuthRequired' => true, 'userSessionEnforced' => false, ]; - $http401 = new EmptyResponse(401); + $http401 = HTTP::respEmpty(401); if ($type === "login") { return [ // conf, user, data, result @@ -532,7 +532,7 @@ LONG_STRING; 'user' => $this->userId, 'password' => "secret", ]; - $exp = new EmptyResponse(500); + $exp = HTTP::respEmpty(500); $this->assertMessage($exp, $this->req($data)); } diff --git a/tests/cases/REST/TinyTinyRSS/TestIcon.php b/tests/cases/REST/TinyTinyRSS/TestIcon.php index f541f504..ecfb9920 100644 --- a/tests/cases/REST/TinyTinyRSS/TestIcon.php +++ b/tests/cases/REST/TinyTinyRSS/TestIcon.php @@ -9,10 +9,10 @@ namespace JKingWeb\Arsse\TestCase\REST\TinyTinyRSS; use JKingWeb\Arsse\Arsse; use JKingWeb\Arsse\User; use JKingWeb\Arsse\Database; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\REST\TinyTinyRSS\Icon; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\EmptyResponse as Response; /** @covers \JKingWeb\Arsse\REST\TinyTinyRSS\Icon */ class TestIcon extends \JKingWeb\Arsse\Test\AbstractTest { @@ -51,21 +51,21 @@ class TestIcon extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->subscriptionIcon->with($this->anything(), 2112, false)->returns(['url' => "http://example.net/logo.png"]); $this->dbMock->subscriptionIcon->with($this->anything(), 1337, false)->returns(['url' => "http://example.org/icon.gif\r\nLocation: http://bad.example.com/"]); // these requests should succeed - $exp = new Response(301, ['Location' => "http://example.com/favicon.ico"]); + $exp = HTTP::respEmpty(301, ['Location' => "http://example.com/favicon.ico"]); $this->assertMessage($exp, $this->req("42.ico")); - $exp = new Response(301, ['Location' => "http://example.net/logo.png"]); + $exp = HTTP::respEmpty(301, ['Location' => "http://example.net/logo.png"]); $this->assertMessage($exp, $this->req("2112.ico")); - $exp = new Response(301, ['Location' => "http://example.org/icon.gif"]); + $exp = HTTP::respEmpty(301, ['Location' => "http://example.org/icon.gif"]); $this->assertMessage($exp, $this->req("1337.ico")); // these requests should fail - $exp = new Response(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("ook.ico")); $this->assertMessage($exp, $this->req("ook")); $this->assertMessage($exp, $this->req("47.ico")); $this->assertMessage($exp, $this->req("2112.png")); $this->assertMessage($exp, $this->req("1123.ico")); // only GET is allowed - $exp = new Response(405, ['Allow' => "GET"]); + $exp = HTTP::respEmpty(405, ['Allow' => "GET"]); $this->assertMessage($exp, $this->req("2112.ico", "PUT")); } @@ -79,32 +79,32 @@ class TestIcon extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->subscriptionIcon->with(null, 2112, false)->returns($url); $this->dbMock->subscriptionIcon->with(null, 1337, false)->returns($url); // these requests should succeed - $exp = new Response(301, ['Location' => "http://example.org/icon.gif"]); + $exp = HTTP::respEmpty(301, ['Location' => "http://example.org/icon.gif"]); $this->assertMessage($exp, $this->req("42.ico")); $this->assertMessage($exp, $this->req("2112.ico")); $this->assertMessage($exp, $this->req("1337.ico")); $this->assertMessage($exp, $this->reqAuth("42.ico")); $this->assertMessage($exp, $this->reqAuth("1337.ico")); // these requests should fail - $exp = new Response(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->reqAuth("2112.ico")); - $exp = new Response(401); + $exp = HTTP::respEmpty(401); $this->assertMessage($exp, $this->reqAuthFailed("42.ico")); $this->assertMessage($exp, $this->reqAuthFailed("1337.ico")); // with HTTP auth required, only authenticated requests should succeed self::setConf(['userHTTPAuthRequired' => true]); - $exp = new Response(301, ['Location' => "http://example.org/icon.gif"]); + $exp = HTTP::respEmpty(301, ['Location' => "http://example.org/icon.gif"]); $this->assertMessage($exp, $this->reqAuth("42.ico")); $this->assertMessage($exp, $this->reqAuth("1337.ico")); // anything else should fail - $exp = new Response(401); + $exp = HTTP::respEmpty(401); $this->assertMessage($exp, $this->req("42.ico")); $this->assertMessage($exp, $this->req("2112.ico")); $this->assertMessage($exp, $this->req("1337.ico")); $this->assertMessage($exp, $this->reqAuthFailed("42.ico")); $this->assertMessage($exp, $this->reqAuthFailed("1337.ico")); // resources for the wrtong user should still fail, too - $exp = new Response(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->reqAuth("2112.ico")); } } From e588a52e88e86d7ab2e157d661f54da83099ba7c Mon Sep 17 00:00:00 2001 From: "J. King" Date: Thu, 4 Aug 2022 22:15:43 -0400 Subject: [PATCH 06/16] Replace ServerRequestFactory --- lib/REST.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/REST.php b/lib/REST.php index 56dbf11c..ded5ef7a 100644 --- a/lib/REST.php +++ b/lib/REST.php @@ -11,7 +11,7 @@ use JKingWeb\Arsse\Misc\HTTP; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\ServerRequestFactory; +use GuzzleHttp\Psr7\ServerRequest; class REST { public const API_LIST = [ @@ -84,7 +84,7 @@ class REST { // ensure the require extensions are loaded Arsse::checkExtensions(...Arsse::REQUIRED_EXTENSIONS); // create a request object if not provided - $req = $req ?? ServerRequestFactory::fromGlobals(); + $req = $req ?? ServerRequest::fromGlobals(); // find the API to handle [, $target, $class] = $this->apiMatch($req->getRequestTarget(), $this->apis); // authenticate the request pre-emptively From 4d18bf27e2d2662422548e6d64e2accee7149e74 Mon Sep 17 00:00:00 2001 From: "J. King" Date: Fri, 5 Aug 2022 22:08:36 -0400 Subject: [PATCH 07/16] Adjust most uses of Diactoros to Guzzle PSR-7 --- lib/Misc/HTTP.php | 6 +- lib/REST/Fever/API.php | 3 +- lib/REST/Miniflux/V1.php | 45 +++-- lib/REST/NextcloudNews/V1_2.php | 19 +- lib/REST/NextcloudNews/Versions.php | 3 +- lib/REST/TinyTinyRSS/API.php | 9 +- tests/cases/REST/Fever/TestAPI.php | 37 ++-- tests/cases/REST/Miniflux/TestV1.php | 165 +++++++++--------- tests/cases/REST/NextcloudNews/TestV1_2.php | 35 ++-- .../cases/REST/NextcloudNews/TestVersions.php | 3 +- tests/cases/REST/TinyTinyRSS/TestAPI.php | 11 +- tests/lib/AbstractTest.php | 15 +- 12 files changed, 173 insertions(+), 178 deletions(-) diff --git a/lib/Misc/HTTP.php b/lib/Misc/HTTP.php index cd78b380..b772ad2e 100644 --- a/lib/Misc/HTTP.php +++ b/lib/Misc/HTTP.php @@ -14,7 +14,11 @@ class HTTP { public static function matchType(MessageInterface $msg, string ...$type): bool { $header = $msg->getHeaderLine("Content-Type") ?? ""; foreach ($type as $t) { - $pattern = "/^".preg_quote(trim($t), "/")."\s*($|;|,)/Di"; + if (($t[0] ?? "") === "+") { + $pattern = "/^[^+;,\s]*".preg_quote(trim($t), "/")."\s*($|;|,)/Di"; + } else { + $pattern = "/^".preg_quote(trim($t), "/")."\s*($|;|,)/Di"; + } if (preg_match($pattern, $header)) { return true; } diff --git a/lib/REST/Fever/API.php b/lib/REST/Fever/API.php index 72f3e9b7..aa900c91 100644 --- a/lib/REST/Fever/API.php +++ b/lib/REST/Fever/API.php @@ -14,7 +14,6 @@ use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Db\ExceptionInput; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\JsonResponse; use Laminas\Diactoros\Response\XmlResponse; class API extends \JKingWeb\Arsse\REST\AbstractHandler { @@ -183,7 +182,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { $d->appendChild($this->makeXMLAssoc($data, $d->createElement("response"))); return new XmlResponse($d->saveXML()); } else { - return new JsonResponse($data, 200, [], \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); + return HTTP::respJson($data, 200, [], \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); } } diff --git a/lib/REST/Miniflux/V1.php b/lib/REST/Miniflux/V1.php index 4ed828a9..bfdf678f 100644 --- a/lib/REST/Miniflux/V1.php +++ b/lib/REST/Miniflux/V1.php @@ -27,7 +27,6 @@ use JKingWeb\Arsse\User\ExceptionConflict; use JKingWeb\Arsse\User\Exception as UserException; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\JsonResponse as Response; use Laminas\Diactoros\Response\TextResponse as GenericResponse; use Laminas\Diactoros\Uri; @@ -534,17 +533,17 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { // TODO: This needs to be refined once PicoFeed is replaced $out[] = ['title' => "Feed", 'type' => "rss", 'url' => $url]; } - return new Response($out); + return HTTP::respJson($out); } protected function getUsers(): ResponseInterface { $tr = Arsse::$user->begin(); - return new Response($this->listUsers(Arsse::$user->list(), false)); + return HTTP::respJson($this->listUsers(Arsse::$user->list(), false)); } protected function getUserById(array $path): ResponseInterface { try { - return new Response($this->listUsers([$path[1]], true)[0] ?? new \stdClass); + return HTTP::respJson($this->listUsers([$path[1]], true)[0] ?? new \stdClass); } catch (UserException $e) { return new ErrorResponse("404", 404); } @@ -553,14 +552,14 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { protected function getUserByNum(array $path): ResponseInterface { try { $user = Arsse::$user->lookup((int) $path[1]); - return new Response($this->listUsers([$user], true)[0] ?? new \stdClass); + return HTTP::respJson($this->listUsers([$user], true)[0] ?? new \stdClass); } catch (UserException $e) { return new ErrorResponse("404", 404); } } protected function getCurrentUser(): ResponseInterface { - return new Response($this->listUsers([Arsse::$user->id], false)[0] ?? new \stdClass); + return HTTP::respJson($this->listUsers([Arsse::$user->id], false)[0] ?? new \stdClass); } protected function createUser(array $data): ResponseInterface { @@ -582,7 +581,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } throw $e; // @codeCoverageIgnore } - return new Response($out, 201); + return HTTP::respJson($out, 201); } protected function updateUserByNum(array $path, array $data): ResponseInterface { @@ -628,7 +627,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } throw $e; // @codeCoverageIgnore } - return new Response($out, 201); + return HTTP::respJson($out, 201); } protected function deleteUserByNum(array $path): ResponseInterface { @@ -667,7 +666,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { // always add 1 to the ID since the root folder will always be 1 instead of 0. $out[] = ['id' => $f['id'] + 1, 'title' => $f['name'], 'user_id' => $meta['num']]; } - return new Response($out); + return HTTP::respJson($out); } protected function createCategory(array $data): ResponseInterface { @@ -681,7 +680,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } } $meta = Arsse::$user->propertiesGet(Arsse::$user->id, false); - return new Response(['id' => $id + 1, 'title' => $data['title'], 'user_id' => $meta['num']], 201); + return HTTP::respJson(['id' => $id + 1, 'title' => $data['title'], 'user_id' => $meta['num']], 201); } protected function updateCategory(array $path, array $data): ResponseInterface { @@ -708,7 +707,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } } $meta = Arsse::$user->propertiesGet(Arsse::$user->id, false); - return new Response(['id' => (int) $path[1], 'title' => $title, 'user_id' => $meta['num']], 201); + return HTTP::respJson(['id' => (int) $path[1], 'title' => $title, 'user_id' => $meta['num']], 201); } protected function deleteCategory(array $path): ResponseInterface { @@ -772,7 +771,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { foreach (Arsse::$db->subscriptionList(Arsse::$user->id) as $r) { $out[] = $this->transformFeed($r, $meta['num'], $meta['root'], $meta['tz']); } - return new Response($out); + return HTTP::respJson($out); } protected function getCategoryFeeds(array $path): ResponseInterface { @@ -792,7 +791,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { // the folder does not exist return new ErrorResponse("404", 404); } - return new Response($out); + return HTTP::respJson($out); } protected function getFeed(array $path): ResponseInterface { @@ -800,7 +799,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { $meta = $this->userMeta(Arsse::$user->id); try { $sub = Arsse::$db->subscriptionPropertiesGet(Arsse::$user->id, (int) $path[1]); - return new Response($this->transformFeed($sub, $meta['num'], $meta['root'], $meta['tz'])); + return HTTP::respJson($this->transformFeed($sub, $meta['num'], $meta['root'], $meta['tz'])); } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } @@ -834,7 +833,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { return new ErrorResponse("DuplicateFeed", 409); } } - return new Response(['feed_id' => $id], 201); + return HTTP::respJson(['feed_id' => $id], 201); } protected function updateFeed(array $path, array $data): ResponseInterface { @@ -881,7 +880,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { if (!$icon || !$icon['type'] || !$icon['data']) { return new ErrorResponse("404", 404); } - return new Response([ + return HTTP::respJson([ 'id' => (int) $icon['id'], 'data' => $icon['type'].";base64,".base64_encode($icon['data']), 'mime_type' => $icon['type'], @@ -1038,7 +1037,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { protected function getEntries(array $query): ResponseInterface { try { - return new Response($this->listEntries($query, new Context)); + return HTTP::respJson($this->listEntries($query, new Context)); } catch (ExceptionInput $e) { return new ErrorResponse("MissingCategory", 400); } @@ -1047,7 +1046,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { protected function getFeedEntries(array $path, array $query): ResponseInterface { $c = (new Context)->subscription((int) $path[1]); try { - return new Response($this->listEntries($query, $c)); + return HTTP::respJson($this->listEntries($query, $c)); } catch (ExceptionInput $e) { // FIXME: this should differentiate between a missing feed and a missing category, but doesn't return new ErrorResponse("404", 404); @@ -1057,7 +1056,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { protected function getCategoryEntries(array $path, array $query): ResponseInterface { $query['category_id'] = (int) $path[1]; try { - return new Response($this->listEntries($query, new Context)); + return HTTP::respJson($this->listEntries($query, new Context)); } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } @@ -1065,7 +1064,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { protected function getEntry(array $path): ResponseInterface { try { - return new Response($this->findEntry((int) $path[1])); + return HTTP::respJson($this->findEntry((int) $path[1])); } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } @@ -1074,7 +1073,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { protected function getFeedEntry(array $path): ResponseInterface { $c = (new Context)->subscription((int) $path[1]); try { - return new Response($this->findEntry((int) $path[3], $c)); + return HTTP::respJson($this->findEntry((int) $path[3], $c)); } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } @@ -1088,7 +1087,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { $c->folder((int) $path[1] - 1); } try { - return new Response($this->findEntry((int) $path[3], $c)); + return HTTP::respJson($this->findEntry((int) $path[3], $c)); } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } @@ -1200,7 +1199,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (FeedException $e) { return new ErrorResponse(["FailedImportFeed", 'url' => $e->getParams()['url'], 'code' => $e->getCode()], 502); } - return new Response(['message' => Arsse::$lang->msg("API.Miniflux.ImportSuccess")]); + return HTTP::respJson(['message' => Arsse::$lang->msg("API.Miniflux.ImportSuccess")]); } protected function opmlExport(): ResponseInterface { diff --git a/lib/REST/NextcloudNews/V1_2.php b/lib/REST/NextcloudNews/V1_2.php index 205fa732..f11eee95 100644 --- a/lib/REST/NextcloudNews/V1_2.php +++ b/lib/REST/NextcloudNews/V1_2.php @@ -17,7 +17,6 @@ use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\REST\Exception; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\JsonResponse as Response; class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { public const VERSION = "11.0.5"; @@ -283,7 +282,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { foreach (Arsse::$db->folderList(Arsse::$user->id, null, false) as $folder) { $folders[] = $this->folderTranslate($folder); } - return new Response(['folders' => $folders]); + return HTTP::respJson(['folders' => $folders]); } // create a folder @@ -302,7 +301,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { } } $folder = $this->folderTranslate(Arsse::$db->folderPropertiesGet(Arsse::$user->id, $folder)); - return new Response(['folders' => [$folder]]); + return HTTP::respJson(['folders' => [$folder]]); } // delete a folder @@ -369,7 +368,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { // since in our implementation feeds don't belong the users, the 'userId' field will always be an empty string $out[] = ['id' => (int) $feed, 'userId' => ""]; } - return new Response(['feeds' => $out]); + return HTTP::respJson(['feeds' => $out]); } // refresh a feed @@ -421,7 +420,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { if ($newest) { $out['newestItemId'] = $newest; } - return new Response($out); + return HTTP::respJson($out); } // return list of feeds for the logged-in user @@ -437,7 +436,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { if ($newest) { $out['newestItemId'] = $newest; } - return new Response($out); + return HTTP::respJson($out); } // delete a feed @@ -585,7 +584,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { $out[] = $this->articleTranslate($item); } $out = ['items' => $out]; - return new Response($out); + return HTTP::respJson($out); } // mark all articles as read @@ -663,7 +662,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { } protected function userStatus(array $url, array $data): ResponseInterface { - return new Response([ + return HTTP::respJson([ 'userId' => (string) Arsse::$user->id, 'displayName' => (string) Arsse::$user->id, 'lastLoginTimestamp' => time(), @@ -689,14 +688,14 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { // return the server version protected function serverVersion(array $url, array $data): ResponseInterface { - return new Response([ + return HTTP::respJson([ 'version' => self::VERSION, 'arsse_version' => Arsse::VERSION, ]); } protected function serverStatus(array $url, array $data): ResponseInterface { - return new Response([ + return HTTP::respJson([ 'version' => self::VERSION, 'arsse_version' => Arsse::VERSION, 'warnings' => [ diff --git a/lib/REST/NextcloudNews/Versions.php b/lib/REST/NextcloudNews/Versions.php index 503fef14..0a3a6f6f 100644 --- a/lib/REST/NextcloudNews/Versions.php +++ b/lib/REST/NextcloudNews/Versions.php @@ -9,7 +9,6 @@ namespace JKingWeb\Arsse\REST\NextcloudNews; use JKingWeb\Arsse\Misc\HTTP; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\JsonResponse as Response; class Versions implements \JKingWeb\Arsse\REST\Handler { public function __construct() { @@ -31,7 +30,7 @@ class Versions implements \JKingWeb\Arsse\REST\Handler { 'v1-2', ], ]; - return new Response($out); + return HTTP::respJson($out); default: // if any other method was used, this is an error return HTTP::respEmpty(405, ['Allow' => "HEAD,GET"]); diff --git a/lib/REST/TinyTinyRSS/API.php b/lib/REST/TinyTinyRSS/API.php index d8fb5cac..0ec6aaf7 100644 --- a/lib/REST/TinyTinyRSS/API.php +++ b/lib/REST/TinyTinyRSS/API.php @@ -21,7 +21,6 @@ use JKingWeb\Arsse\Db\ResultEmpty; use JKingWeb\Arsse\Feed\Exception as FeedException; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\JsonResponse as Response; class API extends \JKingWeb\Arsse\REST\AbstractHandler { public const LEVEL = 15; // emulated API level @@ -110,7 +109,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { // only JSON entities are allowed, but Content-Type is ignored, as is request method $data = @json_decode($data, true); if (json_last_error() !== \JSON_ERROR_NONE || !is_array($data)) { - return new Response(self::FATAL_ERR); + return HTTP::respJson(self::FATAL_ERR); } try { // normalize input @@ -136,13 +135,13 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { // TT-RSS operations are case-insensitive by dint of PHP method names being case-insensitive; this will only trigger if the method really doesn't exist throw new Exception("UNKNOWN_METHOD", ['method' => $data['op']]); } - return new Response([ + return HTTP::respJson([ 'seq' => $data['seq'], 'status' => 0, 'content' => $this->$method($data), ]); } catch (Exception $e) { - return new Response([ + return HTTP::respJson([ 'seq' => $data['seq'], 'status' => 1, 'content' => $e->getData(), @@ -152,7 +151,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { } } else { // absence of a request body indicates an error - return new Response(self::FATAL_ERR); + return HTTP::respJson(self::FATAL_ERR); } } diff --git a/tests/cases/REST/Fever/TestAPI.php b/tests/cases/REST/Fever/TestAPI.php index 59d1858c..2f624da1 100644 --- a/tests/cases/REST/Fever/TestAPI.php +++ b/tests/cases/REST/Fever/TestAPI.php @@ -16,7 +16,6 @@ use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\Db\Transaction; use JKingWeb\Arsse\REST\Fever\API; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\JsonResponse; use Laminas\Diactoros\Response\XmlResponse; /** @covers \JKingWeb\Arsse\REST\Fever\API */ @@ -192,8 +191,8 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { } public function provideTokenAuthenticationRequests(): iterable { - $success = new JsonResponse(['auth' => 1]); - $failure = new JsonResponse(['auth' => 0]); + $success = HTTP::respJson(['auth' => 1]); + $failure = HTTP::respJson(['auth' => 0]); $denied = HTTP::respEmpty(401); return [ [false, true, null, [], ['api' => null], $failure], @@ -255,7 +254,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { ['id' => 2, 'name' => "Interesting", 'subscription' => 1], ['id' => 2, 'name' => "Interesting", 'subscription' => 3], ])); - $exp = new JsonResponse([ + $exp = HTTP::respJson([ 'groups' => [ ['id' => 1, 'title' => "Fascinating"], ['id' => 2, 'title' => "Interesting"], @@ -281,7 +280,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { ['id' => 2, 'name' => "Interesting", 'subscription' => 1], ['id' => 2, 'name' => "Interesting", 'subscription' => 3], ])); - $exp = new JsonResponse([ + $exp = HTTP::respJson([ 'feeds' => [ ['id' => 1, 'favicon_id' => 42, 'title' => "Ankh-Morpork News", 'url' => "http://example.com/feed", 'site_url' => "http://example.com/", 'is_spark' => 0, 'last_updated_on_time' => strtotime("2019-01-01T21:12:00Z")], ['id' => 2, 'favicon_id' => 0, 'title' => "Ook, Ook Eek Ook!", 'url' => "http://example.net/feed", 'site_url' => "http://example.net/", 'is_spark' => 0, 'last_updated_on_time' => strtotime("1988-06-24T12:21:00Z")], @@ -301,7 +300,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { $order = [$desc ? "id desc" : "id"]; $this->dbMock->articleList->returns(new Result($this->articles['db'])); $this->dbMock->articleCount->with($this->userId, (new Context)->hidden(false))->returns(1024); - $exp = new JsonResponse([ + $exp = HTTP::respJson([ 'items' => $this->articles['rest'], 'total_items' => 1024, ]); @@ -330,15 +329,15 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { $unread = [['id' => 4],['id' => 5],['id' => 6]]; $this->dbMock->articleList->with($this->userId, (new Context)->starred(true)->hidden(false))->returns(new Result($saved)); $this->dbMock->articleList->with($this->userId, (new Context)->unread(true)->hidden(false))->returns(new Result($unread)); - $exp = new JsonResponse(['saved_item_ids' => "1,2,3"]); + $exp = HTTP::respJson(['saved_item_ids' => "1,2,3"]); $this->assertMessage($exp, $this->req("api&saved_item_ids")); - $exp = new JsonResponse(['unread_item_ids' => "4,5,6"]); + $exp = HTTP::respJson(['unread_item_ids' => "4,5,6"]); $this->assertMessage($exp, $this->req("api&unread_item_ids")); } public function testListHotLinks(): void { // hot links are not actually implemented, so an empty array should be all we get - $exp = new JsonResponse(['links' => []]); + $exp = HTTP::respJson(['links' => []]); $this->assertMessage($exp, $this->req("api&links")); } @@ -350,7 +349,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->articleList->with($this->userId, (new Context)->unread(true)->hidden(false))->returns(new Result($unread)); $this->dbMock->articleMark->returns(0); $this->dbMock->articleMark->with($this->userId, $this->anything(), (new Context)->article(2112))->throws(new \JKingWeb\Arsse\Db\ExceptionInput("subjectMissing")); - $exp = new JsonResponse($out); + $exp = HTTP::respJson($out); $this->assertMessage($exp, $this->req("api", $post)); if ($c && $data) { $this->dbMock->articleMark->calledWith($this->userId, $data, $this->equalTo($c)); @@ -367,7 +366,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->articleList->with($this->userId, (new Context)->unread(true)->hidden(false))->returns(new Result($unread)); $this->dbMock->articleMark->returns(0); $this->dbMock->articleMark->with($this->userId, $this->anything(), (new Context)->article(2112))->throws(new \JKingWeb\Arsse\Db\ExceptionInput("subjectMissing")); - $exp = new JsonResponse($out); + $exp = HTTP::respJson($out); $this->assertMessage($exp, $this->req("api&$get")); if ($c && $data) { $this->dbMock->articleMark->calledWith($this->userId, $data, $this->equalTo($c)); @@ -423,9 +422,9 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { return [ 'Not an API request' => ["", "", "POST", null, HTTP::respEmpty(404)], 'Wrong method' => ["api", "", "PUT", null, HTTP::respEmpty(405, ['Allow' => "OPTIONS,POST"])], - 'Non-standard method' => ["api", "", "GET", null, new JsonResponse([])], - 'Wrong content type' => ["api", '{"api_key":"validToken"}', "POST", "application/json", new JsonResponse([])], // some clients send nonsensical content types; Fever seems to have allowed this - 'Non-standard content type' => ["api", '{"api_key":"validToken"}', "POST", "multipart/form-data; boundary=33b68964f0de4c1f-5144aa6caaa6e4a8-18bfaf416a1786c8-5c5053a45f221bc1", new JsonResponse([])], // some clients send nonsensical content types; Fever seems to have allowed this + 'Non-standard method' => ["api", "", "GET", null, HTTP::respJson([])], + 'Wrong content type' => ["api", '{"api_key":"validToken"}', "POST", "application/json", HTTP::respJson([])], // some clients send nonsensical content types; Fever seems to have allowed this + 'Non-standard content type' => ["api", '{"api_key":"validToken"}', "POST", "multipart/form-data; boundary=33b68964f0de4c1f-5144aa6caaa6e4a8-18bfaf416a1786c8-5c5053a45f221bc1", HTTP::respJson([])], // some clients send nonsensical content types; Fever seems to have allowed this ]; } @@ -433,21 +432,21 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { $this->hMock->baseResponse->forwards(); $this->hMock->logIn->returns(true); $this->dbMock->subscriptionRefreshed->with($this->userId)->returns(new \DateTimeImmutable("2000-01-01T00:00:00Z")); - $exp = new JsonResponse([ + $exp = HTTP::respJson([ 'api_version' => API::LEVEL, 'auth' => 1, 'last_refreshed_on_time' => 946684800, ]); $this->assertMessage($exp, $this->req("api")); $this->dbMock->subscriptionRefreshed->with($this->userId)->returns(null); // no subscriptions - $exp = new JsonResponse([ + $exp = HTTP::respJson([ 'api_version' => API::LEVEL, 'auth' => 1, 'last_refreshed_on_time' => null, ]); $this->assertMessage($exp, $this->req("api")); $this->hMock->logIn->returns(false); - $exp = new JsonResponse([ + $exp = HTTP::respJson([ 'api_version' => API::LEVEL, 'auth' => 0, ]); @@ -460,7 +459,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->articleList->with($this->userId, $this->equalTo((new Context)->limit(1)->hidden(false)), ["marked_date"], ["marked_date desc"])->returns(new Result([['marked_date' => "2000-01-01 00:00:00"]])); $this->dbMock->articleList->with($this->userId, $this->equalTo((new Context)->unread(true)->hidden(false)))->returns(new Result($unread)); $this->dbMock->articleMark->returns(0); - $exp = new JsonResponse($out); + $exp = HTTP::respJson($out); $this->assertMessage($exp, $this->req("api", ['unread_recently_read' => 1])); $this->dbMock->articleMark->calledWith($this->userId, ['read' => false], $this->equalTo((new Context)->unread(false)->markedRange("1999-12-31T23:59:45Z", null)->hidden(false))); $this->dbMock->articleList->with($this->userId, (new Context)->limit(1)->hidden(false), ["marked_date"], ["marked_date desc"])->returns(new Result([])); @@ -485,7 +484,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { ['id' => 44, 'type' => null, 'data' => "IMAGE DATA"], ['id' => 47, 'type' => null, 'data' => null], ]))); - $exp = new JsonResponse(['favicons' => [ + $exp = HTTP::respJson(['favicons' => [ ['id' => 0, 'data' => $iconType.",".$iconData], ['id' => 42, 'data' => "image/svg+xml;base64,PHN2Zy8+"], ['id' => 44, 'data' => "application/octet-stream;base64,SU1BR0UgREFUQQ=="], diff --git a/tests/cases/REST/Miniflux/TestV1.php b/tests/cases/REST/Miniflux/TestV1.php index 89610474..b1dec747 100644 --- a/tests/cases/REST/Miniflux/TestV1.php +++ b/tests/cases/REST/Miniflux/TestV1.php @@ -26,7 +26,6 @@ use JKingWeb\Arsse\User\ExceptionConflict; use JKingWeb\Arsse\User\ExceptionInput as UserExceptionInput; use JKingWeb\Arsse\Test\Result; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\JsonResponse as Response; use Laminas\Diactoros\Response\TextResponse; /** @covers \JKingWeb\Arsse\REST\Miniflux\V1 */ @@ -182,8 +181,8 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { ['title' => "Feed", 'type' => "rss", 'url' => "http://localhost:8000/Feed/Discovery/Missing"], ]; return [ - ["http://localhost:8000/Feed/Discovery/Valid", new Response($discovered)], - ["http://localhost:8000/Feed/Discovery/Invalid", new Response([])], + ["http://localhost:8000/Feed/Discovery/Valid", HTTP::respJson($discovered)], + ["http://localhost:8000/Feed/Discovery/Invalid", HTTP::respJson([])], ["http://localhost:8000/Feed/Discovery/Missing", new ErrorResponse("Fetch404", 502)], [1, new ErrorResponse(["InvalidInputType", 'field' => "url", 'expected' => "string", 'actual' => "integer"], 422)], ["Not a URL", new ErrorResponse(["InvalidInputValue", 'field' => "url"], 422)], @@ -226,16 +225,16 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideUserQueries(): iterable { self::clearData(); return [ - [true, "/users", new Response(self::USERS)], - [true, "/me", new Response(self::USERS[0])], - [true, "/users/john.doe@example.com", new Response(self::USERS[0])], - [true, "/users/1", new Response(self::USERS[0])], - [true, "/users/jane.doe@example.com", new Response(self::USERS[1])], - [true, "/users/2", new Response(self::USERS[1])], + [true, "/users", HTTP::respJson(self::USERS)], + [true, "/me", HTTP::respJson(self::USERS[0])], + [true, "/users/john.doe@example.com", HTTP::respJson(self::USERS[0])], + [true, "/users/1", HTTP::respJson(self::USERS[0])], + [true, "/users/jane.doe@example.com", HTTP::respJson(self::USERS[1])], + [true, "/users/2", HTTP::respJson(self::USERS[1])], [true, "/users/jack.doe@example.com", new ErrorResponse("404", 404)], [true, "/users/47", new ErrorResponse("404", 404)], [false, "/users", new ErrorResponse("403", 403)], - [false, "/me", new Response(self::USERS[1])], + [false, "/me", HTTP::respJson(self::USERS[1])], [false, "/users/john.doe@example.com", new ErrorResponse("403", 403)], [false, "/users/1", new ErrorResponse("403", 403)], [false, "/users/jane.doe@example.com", new ErrorResponse("403", 403)], @@ -310,16 +309,16 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { [false, "/users/1", ['entry_sorting_direction' => "bad"], null, null, null, null, null, null, new ErrorResponse(["InvalidInputValue", 'field' => "entry_sorting_direction"], 422)], [false, "/users/1", ['theme' => "stark"], null, null, null, null, null, null, new ErrorResponse("403", 403)], [false, "/users/2", ['is_admin' => true], null, null, null, null, null, null, new ErrorResponse("InvalidElevation", 403)], - [false, "/users/2", ['language' => "fr_CA"], null, null, null, null, ['lang' => "fr_CA"], $out1, new Response($resp1, 201)], - [false, "/users/2", ['entry_sorting_direction' => "asc"], null, null, null, null, ['sort_asc' => true], $out1, new Response($resp1, 201)], - [false, "/users/2", ['entry_sorting_direction' => "desc"], null, null, null, null, ['sort_asc' => false], $out1, new Response($resp1, 201)], + [false, "/users/2", ['language' => "fr_CA"], null, null, null, null, ['lang' => "fr_CA"], $out1, HTTP::respJson($resp1, 201)], + [false, "/users/2", ['entry_sorting_direction' => "asc"], null, null, null, null, ['sort_asc' => true], $out1, HTTP::respJson($resp1, 201)], + [false, "/users/2", ['entry_sorting_direction' => "desc"], null, null, null, null, ['sort_asc' => false], $out1, HTTP::respJson($resp1, 201)], [false, "/users/2", ['entries_per_page' => -1], null, null, null, null, ['page_size' => -1], new UserExceptionInput("invalidNonZeroInteger"), new ErrorResponse(["InvalidInputValue", 'field' => "entries_per_page"], 422)], [false, "/users/2", ['timezone' => "Ook"], null, null, null, null, ['tz' => "Ook"], new UserExceptionInput("invalidTimezone"), new ErrorResponse(["InvalidInputValue", 'field' => "timezone"], 422)], [false, "/users/2", ['username' => "j:k"], "j:k", new UserExceptionInput("invalidUsername"), null, null, null, null, new ErrorResponse(["InvalidInputValue", 'field' => "username"], 422)], [false, "/users/2", ['username' => "ook"], "ook", new ExceptionConflict("alreadyExists"), null, null, null, null, new ErrorResponse(["DuplicateUser", 'user' => "ook"], 409)], - [false, "/users/2", ['password' => "ook"], null, null, "ook", "ook", null, null, new Response(array_merge($resp1, ['password' => "ook"]), 201)], - [false, "/users/2", ['username' => "ook", 'password' => "ook"], "ook", true, "ook", "ook", null, null, new Response(array_merge($resp1, ['username' => "ook", 'password' => "ook"]), 201)], - [true, "/users/1", ['theme' => "stark"], null, null, null, null, ['theme' => "stark"], $out2, new Response($resp2, 201)], + [false, "/users/2", ['password' => "ook"], null, null, "ook", "ook", null, null, HTTP::respJson(array_merge($resp1, ['password' => "ook"]), 201)], + [false, "/users/2", ['username' => "ook", 'password' => "ook"], "ook", true, "ook", "ook", null, null, HTTP::respJson(array_merge($resp1, ['username' => "ook", 'password' => "ook"]), 201)], + [true, "/users/1", ['theme' => "stark"], null, null, null, null, ['theme' => "stark"], $out2, HTTP::respJson($resp2, 201)], [true, "/users/3", ['theme' => "stark"], null, null, null, null, null, null, new ErrorResponse("404", 404)], ]; } @@ -367,7 +366,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { [['username' => "j:k", 'password' => "eek"], ["j:k", "eek"], new UserExceptionInput("invalidUsername"), null, null, new ErrorResponse(["InvalidInputValue", 'field' => "username"], 422)], [['username' => "ook", 'password' => "eek", 'timezone' => "ook"], ["ook", "eek"], "eek", ['tz' => "ook"], new UserExceptionInput("invalidTimezone"), new ErrorResponse(["InvalidInputValue", 'field' => "timezone"], 422)], [['username' => "ook", 'password' => "eek", 'entries_per_page' => -1], ["ook", "eek"], "eek", ['page_size' => -1], new UserExceptionInput("invalidNonZeroInteger"), new ErrorResponse(["InvalidInputValue", 'field' => "entries_per_page"], 422)], - [['username' => "ook", 'password' => "eek", 'theme' => "default"], ["ook", "eek"], "eek", ['theme' => "default"], ['theme' => "default"], new Response($resp1, 201)], + [['username' => "ook", 'password' => "eek", 'theme' => "default"], ["ook", "eek"], "eek", ['theme' => "default"], ['theme' => "default"], HTTP::respJson($resp1, 201)], ]; } @@ -406,7 +405,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { ['id' => 1, 'name' => "Science"], ['id' => 20, 'name' => "Technology"], ]))); - $exp = new Response([ + $exp = HTTP::respJson([ ['id' => 1, 'title' => "All", 'user_id' => 42], ['id' => 2, 'title' => "Science", 'user_id' => 42], ['id' => 21, 'title' => "Technology", 'user_id' => 42], @@ -416,7 +415,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { // run test again with a renamed root folder Arsse::$user = $this->createMock(User::class); Arsse::$user->method("propertiesGet")->willReturn(['num' => 47, 'admin' => false, 'root_folder_name' => "Uncategorized"]); - $exp = new Response([ + $exp = HTTP::respJson([ ['id' => 1, 'title' => "Uncategorized", 'user_id' => 47], ['id' => 2, 'title' => "Science", 'user_id' => 47], ['id' => 21, 'title' => "Technology", 'user_id' => 47], @@ -440,7 +439,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideCategoryAdditions(): iterable { return [ - ["New", new Response(['id' => 2112, 'title' => "New", 'user_id' => 42], 201)], + ["New", HTTP::respJson(['id' => 2112, 'title' => "New", 'user_id' => 42], 201)], ["Duplicate", new ErrorResponse(["DuplicateCategory", 'title' => "Duplicate"], 409)], ["", new ErrorResponse(["InvalidCategory", 'title' => ""], 422)], [" ", new ErrorResponse(["InvalidCategory", 'title' => " "], 422)], @@ -467,14 +466,14 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideCategoryUpdates(): iterable { return [ [3, "New", "subjectMissing", new ErrorResponse("404", 404)], - [2, "New", true, new Response(['id' => 2, 'title' => "New", 'user_id' => 42], 201)], + [2, "New", true, HTTP::respJson(['id' => 2, 'title' => "New", 'user_id' => 42], 201)], [2, "Duplicate", "constraintViolation", new ErrorResponse(["DuplicateCategory", 'title' => "Duplicate"], 409)], [2, "", "missing", new ErrorResponse(["InvalidCategory", 'title' => ""], 422)], [2, " ", "whitespace", new ErrorResponse(["InvalidCategory", 'title' => " "], 422)], [2, null, "missing", new ErrorResponse(["MissingInputValue", 'field' => "title"], 422)], [2, false, "subjectMissing", new ErrorResponse(["InvalidInputType", 'field' => "title", 'actual' => "boolean", 'expected' => "string"], 422)], - [1, "New", true, new Response(['id' => 1, 'title' => "New", 'user_id' => 42], 201)], - [1, "Duplicate", "constraintViolation", new Response(['id' => 1, 'title' => "Duplicate", 'user_id' => 42], 201)], // This is allowed because the name of the root folder is only a duplicate in circumstances where it is used + [1, "New", true, HTTP::respJson(['id' => 1, 'title' => "New", 'user_id' => 42], 201)], + [1, "Duplicate", "constraintViolation", HTTP::respJson(['id' => 1, 'title' => "Duplicate", 'user_id' => 42], 201)], // This is allowed because the name of the root folder is only a duplicate in circumstances where it is used [1, "", "missing", new ErrorResponse(["InvalidCategory", 'title' => ""], 422)], [1, " ", "whitespace", new ErrorResponse(["InvalidCategory", 'title' => " "], 422)], [1, null, "missing", new ErrorResponse(["MissingInputValue", 'field' => "title"], 422)], @@ -510,20 +509,20 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function testListFeeds(): void { $this->dbMock->subscriptionList->returns(new Result($this->v(self::FEEDS))); - $exp = new Response(self::FEEDS_OUT); + $exp = HTTP::respJson(self::FEEDS_OUT); $this->assertMessage($exp, $this->req("GET", "/feeds")); } public function testListFeedsOfACategory(): void { $this->dbMock->subscriptionList->returns(new Result($this->v(self::FEEDS))); - $exp = new Response(self::FEEDS_OUT); + $exp = HTTP::respJson(self::FEEDS_OUT); $this->assertMessage($exp, $this->req("GET", "/categories/2112/feeds")); $this->dbMock->subscriptionList->calledWith(Arsse::$user->id, 2111, true); } public function testListFeedsOfTheRootCategory(): void { $this->dbMock->subscriptionList->returns(new Result($this->v(self::FEEDS))); - $exp = new Response(self::FEEDS_OUT); + $exp = HTTP::respJson(self::FEEDS_OUT); $this->assertMessage($exp, $this->req("GET", "/categories/1/feeds")); $this->dbMock->subscriptionList->calledWith(Arsse::$user->id, 0, false); } @@ -537,9 +536,9 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function testGetAFeed(): void { $this->dbMock->subscriptionPropertiesGet->returns($this->v(self::FEEDS[0]))->returns($this->v(self::FEEDS[1])); - $this->assertMessage(new Response(self::FEEDS_OUT[0]), $this->req("GET", "/feeds/1")); + $this->assertMessage(HTTP::respJson(self::FEEDS_OUT[0]), $this->req("GET", "/feeds/1")); $this->dbMock->subscriptionPropertiesGet->calledWith(Arsse::$user->id, 1); - $this->assertMessage(new Response(self::FEEDS_OUT[1]), $this->req("GET", "/feeds/55")); + $this->assertMessage(HTTP::respJson(self::FEEDS_OUT[1]), $this->req("GET", "/feeds/55")); $this->dbMock->subscriptionPropertiesGet->calledWith(Arsse::$user->id, 55); } @@ -634,16 +633,16 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("unsupportedFeedFormat"), null, null, null, new ErrorResponse("FetchFormat", 502)], [['feed_url' => "http://example.com/", 'category_id' => 1], 2112, new ExceptionInput("constraintViolation"), null, null, new ErrorResponse("DuplicateFeed", 409)], [['feed_url' => "http://example.com/", 'category_id' => 1], 2112, 44, new ExceptionInput("idMissing"), null, new ErrorResponse("MissingCategory", 422)], - [['feed_url' => "http://example.com/", 'category_id' => 1], 2112, 44, true, null, new Response(['feed_id' => 44], 201)], - [['feed_url' => "http://example.com/", 'category_id' => 1, 'keeplist_rules' => "^A"], 2112, 44, true, true, new Response(['feed_id' => 44], 201)], - [['feed_url' => "http://example.com/", 'category_id' => 1, 'blocklist_rules' => "A"], 2112, 44, true, true, new Response(['feed_id' => 44], 201)], + [['feed_url' => "http://example.com/", 'category_id' => 1], 2112, 44, true, null, HTTP::respJson(['feed_id' => 44], 201)], + [['feed_url' => "http://example.com/", 'category_id' => 1, 'keeplist_rules' => "^A"], 2112, 44, true, true, HTTP::respJson(['feed_id' => 44], 201)], + [['feed_url' => "http://example.com/", 'category_id' => 1, 'blocklist_rules' => "A"], 2112, 44, true, true, HTTP::respJson(['feed_id' => 44], 201)], ]; } /** @dataProvider provideFeedModifications */ public function testModifyAFeed(array $in, array $data, $out, ResponseInterface $exp): void { $this->h = $this->partialMock(V1::class); - $this->h->getFeed->returns(new Response(self::FEEDS_OUT[0])); + $this->h->getFeed->returns(HTTP::respJson(self::FEEDS_OUT[0])); if ($out instanceof \Exception) { $this->dbMock->subscriptionPropertiesSet->throws($out); } else { @@ -655,7 +654,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideFeedModifications(): iterable { self::clearData(); - $success = new Response(self::FEEDS_OUT[0], 201); + $success = HTTP::respJson(self::FEEDS_OUT[0], 201); return [ [[], [], true, $success], [[], [], new ExceptionInput("subjectMissing"), new ErrorResponse("404", 404)], @@ -672,9 +671,9 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function testModifyAFeedWithNoBody(): void { $this->h = $this->partialMock(V1::class); - $this->h->getFeed->returns(new Response(self::FEEDS_OUT[0])); + $this->h->getFeed->returns(HTTP::respJson(self::FEEDS_OUT[0])); $this->dbMock->subscriptionPropertiesSet->returns(true); - $this->assertMessage(new Response(self::FEEDS_OUT[0], 201), $this->req("PUT", "/feeds/2112", "")); + $this->assertMessage(HTTP::respJson(self::FEEDS_OUT[0], 201), $this->req("PUT", "/feeds/2112", "")); $this->dbMock->subscriptionPropertiesSet->calledWith(Arsse::$user->id, 2112, []); } @@ -703,7 +702,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideIcons(): iterable { return [ - [['id' => 44, 'type' => "image/svg+xml", 'data' => ""], new Response(['id' => 44, 'data' => "image/svg+xml;base64,PHN2Zy8+", 'mime_type' => "image/svg+xml"])], + [['id' => 44, 'type' => "image/svg+xml", 'data' => ""], HTTP::respJson(['id' => 44, 'data' => "image/svg+xml;base64,PHN2Zy8+", 'mime_type' => "image/svg+xml"])], [['id' => 47, 'type' => "", 'data' => ""], new ErrorResponse("404", 404)], [['id' => 47, 'type' => null, 'data' => ""], new ErrorResponse("404", 404)], [['id' => 47, 'type' => null, 'data' => null], new ErrorResponse("404", 404)], @@ -755,50 +754,50 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { ["/entries?order=false", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "order"], 400)], ["/entries?starred&starred", null, null, [], false, new ErrorResponse(["DuplicateInputValue", 'field' => "starred"], 400)], ["/entries?after&after=0", null, null, [], false, new ErrorResponse(["DuplicateInputValue", 'field' => "after"], 400)], - ["/entries", $c, $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?category_id=47", (clone $c)->folder(46), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?category_id=1", (clone $c)->folderShallow(0), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?status=unread", (clone $c)->unread(true)->hidden(false), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?status=read", (clone $c)->unread(false)->hidden(false), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?status=removed", (clone $c)->hidden(true), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?status=unread&status=read", (clone $c)->hidden(false), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?status=unread&status=removed", new UnionContext((clone $c)->unread(true), (clone $c)->hidden(true)), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?status=removed&status=read", new UnionContext((clone $c)->unread(false), (clone $c)->hidden(true)), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?status=removed&status=read&status=removed", new UnionContext((clone $c)->unread(false), (clone $c)->hidden(true)), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?status=removed&status=read&status=unread", $c, $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?starred", (clone $c)->starred(true), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?starred=", (clone $c)->starred(true), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?starred=true", (clone $c)->starred(true), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?starred=false", (clone $c)->starred(true), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?after=0", (clone $c)->modifiedRange(0, null), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?before=0", $c, $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?before=1", (clone $c)->modifiedRange(null, 1), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?before=1&after=0", (clone $c)->modifiedRange(0, 1), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?after_entry_id=42", (clone $c)->articleRange(43, null), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?before_entry_id=47", (clone $c)->articleRange(null, 46), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?search=alpha%20beta", (clone $c)->searchTerms(["alpha", "beta"]), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?limit=4", (clone $c)->limit(4), $o, self::ENTRIES, true, new Response(['total' => 2112, 'entries' => self::ENTRIES_OUT])], - ["/entries?offset=20", (clone $c)->offset(20), $o, [], true, new Response(['total' => 2112, 'entries' => []])], - ["/entries?direction=asc", $c, $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?order=id", $c, ["id"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?order=published_at", $c, ["modified_date"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?order=category_id", $c, ["top_folder"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?order=category_title", $c, ["top_folder_name"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?order=status", $c, ["hidden", "unread desc"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?direction=desc", $c, ["modified_date desc"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?order=id&direction=desc", $c, ["id desc"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?order=published_at&direction=desc", $c, ["modified_date desc"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?order=category_id&direction=desc", $c, ["top_folder desc"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?order=category_title&direction=desc", $c, ["top_folder_name desc"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?order=status&direction=desc", $c, ["hidden desc", "unread"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries", $c, $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?category_id=47", (clone $c)->folder(46), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?category_id=1", (clone $c)->folderShallow(0), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?status=unread", (clone $c)->unread(true)->hidden(false), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?status=read", (clone $c)->unread(false)->hidden(false), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?status=removed", (clone $c)->hidden(true), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?status=unread&status=read", (clone $c)->hidden(false), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?status=unread&status=removed", new UnionContext((clone $c)->unread(true), (clone $c)->hidden(true)), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?status=removed&status=read", new UnionContext((clone $c)->unread(false), (clone $c)->hidden(true)), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?status=removed&status=read&status=removed", new UnionContext((clone $c)->unread(false), (clone $c)->hidden(true)), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?status=removed&status=read&status=unread", $c, $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?starred", (clone $c)->starred(true), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?starred=", (clone $c)->starred(true), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?starred=true", (clone $c)->starred(true), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?starred=false", (clone $c)->starred(true), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?after=0", (clone $c)->modifiedRange(0, null), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?before=0", $c, $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?before=1", (clone $c)->modifiedRange(null, 1), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?before=1&after=0", (clone $c)->modifiedRange(0, 1), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?after_entry_id=42", (clone $c)->articleRange(43, null), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?before_entry_id=47", (clone $c)->articleRange(null, 46), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?search=alpha%20beta", (clone $c)->searchTerms(["alpha", "beta"]), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?limit=4", (clone $c)->limit(4), $o, self::ENTRIES, true, HTTP::respJson(['total' => 2112, 'entries' => self::ENTRIES_OUT])], + ["/entries?offset=20", (clone $c)->offset(20), $o, [], true, HTTP::respJson(['total' => 2112, 'entries' => []])], + ["/entries?direction=asc", $c, $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?order=id", $c, ["id"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?order=published_at", $c, ["modified_date"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?order=category_id", $c, ["top_folder"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?order=category_title", $c, ["top_folder_name"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?order=status", $c, ["hidden", "unread desc"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?direction=desc", $c, ["modified_date desc"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?order=id&direction=desc", $c, ["id desc"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?order=published_at&direction=desc", $c, ["modified_date desc"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?order=category_id&direction=desc", $c, ["top_folder desc"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?order=category_title&direction=desc", $c, ["top_folder_name desc"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?order=status&direction=desc", $c, ["hidden desc", "unread"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], ["/entries?category_id=2112", (clone $c)->folder(2111), $o, new ExceptionInput("idMissing"), false, new ErrorResponse("MissingCategory")], - ["/feeds/42/entries", (clone $c)->subscription(42), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/feeds/42/entries?category_id=47", (clone $c)->subscription(42)->folder(46), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/feeds/42/entries", (clone $c)->subscription(42), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/feeds/42/entries?category_id=47", (clone $c)->subscription(42)->folder(46), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], ["/feeds/2112/entries", (clone $c)->subscription(2112), $o, new ExceptionInput("idMissing"), false, new ErrorResponse("404", 404)], - ["/categories/42/entries", (clone $c)->folder(41), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/categories/42/entries?category_id=47", (clone $c)->folder(41), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/categories/42/entries?starred", (clone $c)->folder(41)->starred(true), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/categories/1/entries", (clone $c)->folderShallow(0), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/categories/42/entries", (clone $c)->folder(41), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/categories/42/entries?category_id=47", (clone $c)->folder(41), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/categories/42/entries?starred", (clone $c)->folder(41)->starred(true), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/categories/1/entries", (clone $c)->folderShallow(0), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], ["/categories/2112/entries", (clone $c)->folder(2111), $o, new ExceptionInput("idMissing"), false, new ErrorResponse("404", 404)], ]; } @@ -828,17 +827,17 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { self::clearData(); $c = new Context; return [ - ["/entries/42", (clone $c)->article(42), [self::ENTRIES[1]], new Response(self::ENTRIES_OUT[1])], + ["/entries/42", (clone $c)->article(42), [self::ENTRIES[1]], HTTP::respJson(self::ENTRIES_OUT[1])], ["/entries/2112", (clone $c)->article(2112), new ExceptionInput("subjectMissing"), new ErrorResponse("404", 404)], - ["/feeds/47/entries/42", (clone $c)->subscription(47)->article(42), [self::ENTRIES[1]], new Response(self::ENTRIES_OUT[1])], + ["/feeds/47/entries/42", (clone $c)->subscription(47)->article(42), [self::ENTRIES[1]], HTTP::respJson(self::ENTRIES_OUT[1])], ["/feeds/47/entries/44", (clone $c)->subscription(47)->article(44), [], new ErrorResponse("404", 404)], ["/feeds/47/entries/2112", (clone $c)->subscription(47)->article(2112), new ExceptionInput("subjectMissing"), new ErrorResponse("404", 404)], ["/feeds/2112/entries/47", (clone $c)->subscription(2112)->article(47), new ExceptionInput("idMissing"), new ErrorResponse("404", 404)], - ["/categories/47/entries/42", (clone $c)->folder(46)->article(42), [self::ENTRIES[1]], new Response(self::ENTRIES_OUT[1])], + ["/categories/47/entries/42", (clone $c)->folder(46)->article(42), [self::ENTRIES[1]], HTTP::respJson(self::ENTRIES_OUT[1])], ["/categories/47/entries/44", (clone $c)->folder(46)->article(44), [], new ErrorResponse("404", 404)], ["/categories/47/entries/2112", (clone $c)->folder(46)->article(2112), new ExceptionInput("subjectMissing"), new ErrorResponse("404", 404)], ["/categories/2112/entries/47", (clone $c)->folder(2111)->article(47), new ExceptionInput("idMissing"), new ErrorResponse("404", 404)], - ["/categories/1/entries/42", (clone $c)->folderShallow(0)->article(42), [self::ENTRIES[1]], new Response(self::ENTRIES_OUT[1])], + ["/categories/1/entries/42", (clone $c)->folderShallow(0)->article(42), [self::ENTRIES[1]], HTTP::respJson(self::ENTRIES_OUT[1])], ]; } @@ -970,7 +969,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { [new ImportException("invalidFolderCopy"), new ErrorResponse("DuplicateImportCategory", 422)], [new ImportException("invalidTagName"), new ErrorResponse("InvalidImportLabel", 422)], [new FeedException("invalidUrl", ['url' => "http://example.com/"]), new ErrorResponse(["FailedImportFeed", 'url' => "http://example.com/", 'code' => 10502], 502)], - [true, new Response(['message' => Arsse::$lang->msg("API.Miniflux.ImportSuccess")])], + [true, HTTP::respJson(['message' => Arsse::$lang->msg("API.Miniflux.ImportSuccess")])], ]; } diff --git a/tests/cases/REST/NextcloudNews/TestV1_2.php b/tests/cases/REST/NextcloudNews/TestV1_2.php index 08f1f709..71b5eab8 100644 --- a/tests/cases/REST/NextcloudNews/TestV1_2.php +++ b/tests/cases/REST/NextcloudNews/TestV1_2.php @@ -17,7 +17,6 @@ use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\Db\Transaction; use JKingWeb\Arsse\REST\NextcloudNews\V1_2; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\JsonResponse as Response; /** @covers \JKingWeb\Arsse\REST\NextcloudNews\V1_2 */ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { @@ -408,7 +407,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { ['id' => 12, 'name' => "Hardware"], ]; $this->dbMock->folderList->with($this->userId, null, false)->returns(new Result($this->v($list))); - $exp = new Response(['folders' => $out]); + $exp = HTTP::respJson(['folders' => $out]); $this->assertMessage($exp, $this->req("GET", "/folders")); } @@ -432,10 +431,10 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideFolderCreations(): array { return [ - [['name' => "Software"], true, 1, new Response(['folders' => [['id' => 1, 'name' => "Software"]]])], - [['name' => "Software"], false, 1, new Response(['folders' => [['id' => 1, 'name' => "Software"]]])], - [['name' => "Hardware"], true, "2", new Response(['folders' => [['id' => 2, 'name' => "Hardware"]]])], - [['name' => "Hardware"], false, "2", new Response(['folders' => [['id' => 2, 'name' => "Hardware"]]])], + [['name' => "Software"], true, 1, HTTP::respJson(['folders' => [['id' => 1, 'name' => "Software"]]])], + [['name' => "Software"], false, 1, HTTP::respJson(['folders' => [['id' => 1, 'name' => "Software"]]])], + [['name' => "Hardware"], true, "2", HTTP::respJson(['folders' => [['id' => 2, 'name' => "Hardware"]]])], + [['name' => "Hardware"], false, "2", HTTP::respJson(['folders' => [['id' => 2, 'name' => "Hardware"]]])], [['name' => "Software"], true, new ExceptionInput("constraintViolation"), HTTP::respEmpty(409)], [['name' => ""], true, new ExceptionInput("whitespace"), HTTP::respEmpty(422)], [['name' => " "], true, new ExceptionInput("whitespace"), HTTP::respEmpty(422)], @@ -477,7 +476,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { } public function testRetrieveServerVersion(): void { - $exp = new Response([ + $exp = HTTP::respJson([ 'version' => V1_2::VERSION, 'arsse_version' => Arsse::VERSION, ]); @@ -497,9 +496,9 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->subscriptionList->with($this->userId)->returns(new Result([]))->returns(new Result($this->v($this->feeds['db']))); $this->dbMock->articleStarred->with($this->userId)->returns($this->v(['total' => 0]))->returns($this->v(['total' => 5])); $this->dbMock->editionLatest->with($this->userId)->returns(0)->returns(4758915); - $exp = new Response($exp1); + $exp = HTTP::respJson($exp1); $this->assertMessage($exp, $this->req("GET", "/feeds")); - $exp = new Response($exp2); + $exp = HTTP::respJson($exp2); $this->assertMessage($exp, $this->req("GET", "/feeds")); } @@ -538,12 +537,12 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideNewSubscriptions(): array { $feedException = new \JKingWeb\Arsse\Feed\Exception("", [], new \PicoFeed\Reader\SubscriptionNotFoundException); return [ - [['url' => "http://example.com/news.atom", 'folderId' => 3], 2112, 0, $this->feeds['db'][0], new ExceptionInput("idMissing"), new Response(['feeds' => [$this->feeds['rest'][0]]])], - [['url' => "http://example.org/news.atom", 'folderId' => 8], 42, 4758915, $this->feeds['db'][1], true, new Response(['feeds' => [$this->feeds['rest'][1]], 'newestItemId' => 4758915])], + [['url' => "http://example.com/news.atom", 'folderId' => 3], 2112, 0, $this->feeds['db'][0], new ExceptionInput("idMissing"), HTTP::respJson(['feeds' => [$this->feeds['rest'][0]]])], + [['url' => "http://example.org/news.atom", 'folderId' => 8], 42, 4758915, $this->feeds['db'][1], true, HTTP::respJson(['feeds' => [$this->feeds['rest'][1]], 'newestItemId' => 4758915])], [['url' => "http://example.com/news.atom", 'folderId' => 3], new ExceptionInput("constraintViolation"), 0, $this->feeds['db'][0], new ExceptionInput("idMissing"), HTTP::respEmpty(409)], [['url' => "http://example.org/news.atom", 'folderId' => 8], new ExceptionInput("constraintViolation"), 4758915, $this->feeds['db'][1], true, HTTP::respEmpty(409)], [[], $feedException, 0, [], false, HTTP::respEmpty(422)], - [['url' => "http://example.net/news.atom", 'folderId' => -1], 47, 2112, $this->feeds['db'][2], new ExceptionInput("typeViolation"), new Response(['feeds' => [$this->feeds['rest'][2]], 'newestItemId' => 2112])], + [['url' => "http://example.net/news.atom", 'folderId' => -1], 47, 2112, $this->feeds['db'][2], new ExceptionInput("typeViolation"), HTTP::respJson(['feeds' => [$this->feeds['rest'][2]], 'newestItemId' => 2112])], ]; } @@ -627,7 +626,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { ], ]; $this->dbMock->feedListStale->returns($this->v(array_column($out, "id"))); - $exp = new Response(['feeds' => $out]); + $exp = HTTP::respJson(['feeds' => $out]); $this->assertMessage($exp, $this->req("GET", "/feeds/all")); } @@ -683,7 +682,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $c = (new Context)->hidden(false); $t = Date::normalize(time()); $out = new Result($this->v($this->articles['db'])); - $r200 = new Response(['items' => $this->articles['rest']]); + $r200 = HTTP::respJson(['items' => $this->articles['rest']]); $r422 = HTTP::respEmpty(422); return [ ["/items", [], clone $c, $out, $r200], @@ -854,7 +853,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { ]; $arr2['warnings']['improperlyConfiguredCron'] = true; $arr2['warnings']['incorrectDbCharset'] = true; - $exp = new Response($arr1); + $exp = HTTP::respJson($arr1); $this->assertMessage($exp, $this->req("GET", "/status")); } @@ -888,10 +887,10 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { public function testQueryTheUserStatus(): void { $act = $this->req("GET", "/user"); - $exp = new Response([ + $exp = HTTP::respJson([ 'userId' => $this->userId, 'displayName' => $this->userId, - 'lastLoginTimestamp' => $this->approximateTime($act->getPayload()['lastLoginTimestamp'], new \DateTimeImmutable), + 'lastLoginTimestamp' => $this->approximateTime(json_decode((string) $act->getBody(), true)['lastLoginTimestamp'], new \DateTimeImmutable), 'avatar' => null, ]); $this->assertMessage($exp, $act); @@ -906,7 +905,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->folderAdd->with($this->anything(), $in)->returns(1); $this->dbMock->folderPropertiesGet->with($this->userId, 1)->returns($this->v($out1)); $this->dbMock->folderPropertiesGet->with($this->userId, 2)->returns($this->v($out2)); - $exp = new Response(['folders' => [$out1]]); + $exp = HTTP::respJson(['folders' => [$out1]]); $this->assertMessage($exp, $this->req("POST", "/folders?name=Hardware", json_encode($in))); } diff --git a/tests/cases/REST/NextcloudNews/TestVersions.php b/tests/cases/REST/NextcloudNews/TestVersions.php index a254772b..472b808f 100644 --- a/tests/cases/REST/NextcloudNews/TestVersions.php +++ b/tests/cases/REST/NextcloudNews/TestVersions.php @@ -9,7 +9,6 @@ namespace JKingWeb\Arsse\TestCase\REST\NextcloudNews; use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\REST\NextcloudNews\Versions; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\JsonResponse as Response; /** @covers \JKingWeb\Arsse\REST\NextcloudNews\Versions */ class TestVersions extends \JKingWeb\Arsse\Test\AbstractTest { @@ -25,7 +24,7 @@ class TestVersions extends \JKingWeb\Arsse\Test\AbstractTest { } public function testFetchVersionList(): void { - $exp = new Response(['apiLevels' => ['v1-2']]); + $exp = HTTP::respJson(['apiLevels' => ['v1-2']]); $this->assertMessage($exp, $this->req("GET", "/")); $this->assertMessage($exp, $this->req("GET", "/")); $this->assertMessage($exp, $this->req("GET", "/")); diff --git a/tests/cases/REST/TinyTinyRSS/TestAPI.php b/tests/cases/REST/TinyTinyRSS/TestAPI.php index d643491f..96d50c30 100644 --- a/tests/cases/REST/TinyTinyRSS/TestAPI.php +++ b/tests/cases/REST/TinyTinyRSS/TestAPI.php @@ -18,7 +18,6 @@ use JKingWeb\Arsse\Db\Transaction; use JKingWeb\Arsse\REST\TinyTinyRSS\API; use JKingWeb\Arsse\Feed\Exception as FeedException; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\JsonResponse as Response; /** @covers \JKingWeb\Arsse\REST\TinyTinyRSS\API * @covers \JKingWeb\Arsse\REST\TinyTinyRSS\Exception */ @@ -166,17 +165,17 @@ LONG_STRING; return $this->req($data, "POST", "", null, $user); } - protected function respGood($content = null, $seq = 0): Response { - return new Response([ + protected function respGood($content = null, $seq = 0): ResponseInterface { + return HTTP::respJson([ 'seq' => $seq, 'status' => 0, 'content' => $content, ]); } - protected function respErr(string $msg, $content = [], $seq = 0): Response { + protected function respErr(string $msg, $content = [], $seq = 0): ResponseInterface { $err = ['error' => $msg]; - return new Response([ + return HTTP::respJson([ 'seq' => $seq, 'status' => 1, 'content' => array_merge($err, $content, $err), @@ -1815,7 +1814,7 @@ LONG_STRING; ])); } - protected function outputHeadlines(int $id): Response { + protected function outputHeadlines(int $id): ResponseInterface { return $this->respGood([ [ 'id' => $id, diff --git a/tests/lib/AbstractTest.php b/tests/lib/AbstractTest.php index 409a6e95..c155a192 100644 --- a/tests/lib/AbstractTest.php +++ b/tests/lib/AbstractTest.php @@ -19,12 +19,12 @@ use JKingWeb\Arsse\Factory; use JKingWeb\Arsse\Misc\Date; use JKingWeb\Arsse\Misc\ValueInfo; use JKingWeb\Arsse\Misc\URL; +use JKingWeb\Arsse\Misc\HTTP; use Psr\Http\Message\MessageInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\ServerRequest; -use Laminas\Diactoros\Response\JsonResponse; use Laminas\Diactoros\Response\XmlResponse; /** @coversNothing */ @@ -191,12 +191,13 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase { $this->assertSame($exp->getMethod(), $act->getMethod(), $text); $this->assertSame($exp->getRequestTarget(), $act->getRequestTarget(), $text); } - if ($exp instanceof JsonResponse) { - $this->assertInstanceOf(JsonResponse::class, $act, $text); - $this->assertEquals($exp->getPayload(), $act->getPayload(), $text); - $this->assertSame($exp->getPayload(), $act->getPayload(), $text); - } elseif ($exp instanceof XmlResponse) { - $this->assertInstanceOf(XmlResponse::class, $act, $text); + if ($exp instanceof ResponseInterface && HTTP::matchType($exp, "application/json", "text/json", "+json")) { + $expBody = json_decode((string) $exp->getBody(), true); + $actBody = json_decode((string) $act->getBody(), true); + $this->assertSame(\JSON_ERROR_NONE, json_last_error(), "Response body is not valid JSON"); + $this->assertEquals($expBody, $actBody, $text); + $this->assertSame($expBody, $actBody, $text); + } elseif ($exp instanceof ResponseInterface && HTTP::matchType($exp, "application/xml", "text/xml", "+xml")) { $this->assertXmlStringEqualsXmlString((string) $exp->getBody(), (string) $act->getBody(), $text); } else { $this->assertSame((string) $exp->getBody(), (string) $act->getBody(), $text); From 64ec3f6ae43fdd080c0ab12110e5c8fad8b8e68f Mon Sep 17 00:00:00 2001 From: "J. King" Date: Fri, 5 Aug 2022 22:10:36 -0400 Subject: [PATCH 08/16] Use unused variable --- tests/cases/REST/NextcloudNews/TestV1_2.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cases/REST/NextcloudNews/TestV1_2.php b/tests/cases/REST/NextcloudNews/TestV1_2.php index 71b5eab8..ea8b824e 100644 --- a/tests/cases/REST/NextcloudNews/TestV1_2.php +++ b/tests/cases/REST/NextcloudNews/TestV1_2.php @@ -906,7 +906,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->folderPropertiesGet->with($this->userId, 1)->returns($this->v($out1)); $this->dbMock->folderPropertiesGet->with($this->userId, 2)->returns($this->v($out2)); $exp = HTTP::respJson(['folders' => [$out1]]); - $this->assertMessage($exp, $this->req("POST", "/folders?name=Hardware", json_encode($in))); + $this->assertMessage($exp, $this->req("POST", $url, json_encode($in))); } public function testMeldJsonAndQueryParameters(): void { From 56f015bfb98f816f84d2056d6f3b1917d5941b64 Mon Sep 17 00:00:00 2001 From: "J. King" Date: Sat, 6 Aug 2022 13:40:02 -0400 Subject: [PATCH 09/16] More Guzzle conversion --- lib/REST/Fever/API.php | 3 +-- lib/REST/Miniflux/Status.php | 3 +-- lib/REST/Miniflux/V1.php | 5 ++--- tests/cases/Misc/TestHTTP.php | 6 ++++-- tests/cases/REST/TestREST.php | 39 +++++++++++++++++------------------ 5 files changed, 27 insertions(+), 29 deletions(-) diff --git a/lib/REST/Fever/API.php b/lib/REST/Fever/API.php index aa900c91..9b243129 100644 --- a/lib/REST/Fever/API.php +++ b/lib/REST/Fever/API.php @@ -14,7 +14,6 @@ use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Db\ExceptionInput; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\XmlResponse; class API extends \JKingWeb\Arsse\REST\AbstractHandler { public const LEVEL = 3; @@ -180,7 +179,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { if ($xml) { $d = new \DOMDocument("1.0", "utf-8"); $d->appendChild($this->makeXMLAssoc($data, $d->createElement("response"))); - return new XmlResponse($d->saveXML()); + return HTTP::respXml($d->saveXML()); } else { return HTTP::respJson($data, 200, [], \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); } diff --git a/lib/REST/Miniflux/Status.php b/lib/REST/Miniflux/Status.php index c829193b..b84f4a13 100644 --- a/lib/REST/Miniflux/Status.php +++ b/lib/REST/Miniflux/Status.php @@ -9,7 +9,6 @@ namespace JKingWeb\Arsse\REST\Miniflux; use JKingWeb\Arsse\Misc\HTTP; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\TextResponse; class Status extends \JKingWeb\Arsse\REST\AbstractHandler { public function __construct() { @@ -32,6 +31,6 @@ class Status extends \JKingWeb\Arsse\REST\AbstractHandler { } elseif ($target === "/healthcheck") { $out = "OK"; } - return new TextResponse($out); + return HTTP::respText($out); } } diff --git a/lib/REST/Miniflux/V1.php b/lib/REST/Miniflux/V1.php index bfdf678f..7ff9df24 100644 --- a/lib/REST/Miniflux/V1.php +++ b/lib/REST/Miniflux/V1.php @@ -27,8 +27,7 @@ use JKingWeb\Arsse\User\ExceptionConflict; use JKingWeb\Arsse\User\Exception as UserException; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\TextResponse as GenericResponse; -use Laminas\Diactoros\Uri; +use GuzzleHttp\Psr7\Uri; class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { public const VERSION = "2.0.28"; @@ -1203,6 +1202,6 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } protected function opmlExport(): ResponseInterface { - return new GenericResponse(Arsse::$obj->get(OPML::class)->export(Arsse::$user->id), 200, ['Content-Type' => "application/xml"]); + return HTTP::respText(Arsse::$obj->get(OPML::class)->export(Arsse::$user->id), 200, ['Content-Type' => "application/xml"]); } } diff --git a/tests/cases/Misc/TestHTTP.php b/tests/cases/Misc/TestHTTP.php index 9bffe073..b4a580ed 100644 --- a/tests/cases/Misc/TestHTTP.php +++ b/tests/cases/Misc/TestHTTP.php @@ -7,14 +7,16 @@ declare(strict_types=1); namespace JKingWeb\Arsse\TestCase\Misc; use JKingWeb\Arsse\Misc\HTTP; +use GuzzleHttp\Psr7\Request; +use GuzzleHttp\Psr7\Response; /** @covers \JKingWeb\Arsse\Misc\HTTP */ class TestHTTP extends \JKingWeb\Arsse\Test\AbstractTest { /** @dataProvider provideMediaTypes */ public function testMatchMediaType(string $header, array $types, bool $exp): void { - $msg = (new \Laminas\Diactoros\Request)->withHeader("Content-Type", $header); + $msg = (new Request("POST", "/"))->withHeader("Content-Type", $header); $this->assertSame($exp, HTTP::matchType($msg, ...$types)); - $msg = (new \Laminas\Diactoros\Response)->withHeader("Content-Type", $header); + $msg = (new Response)->withHeader("Content-Type", $header); $this->assertSame($exp, HTTP::matchType($msg, ...$types)); } diff --git a/tests/cases/REST/TestREST.php b/tests/cases/REST/TestREST.php index 059803da..58dfa524 100644 --- a/tests/cases/REST/TestREST.php +++ b/tests/cases/REST/TestREST.php @@ -15,10 +15,9 @@ use JKingWeb\Arsse\REST\TinyTinyRSS\API as TTRSS; use JKingWeb\Arsse\Misc\HTTP; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Request; -use Laminas\Diactoros\Response; -use Laminas\Diactoros\ServerRequest; -use Laminas\Diactoros\Response\TextResponse; +use GuzzleHttp\Psr7\Response; +use GuzzleHttp\Psr7\Request; +use GuzzleHttp\Psr7\ServerRequest; /** @covers \JKingWeb\Arsse\REST */ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { @@ -70,7 +69,7 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { $this->userMock->auth->with("someone.else@example.com", "")->returns(true); Arsse::$user = $this->userMock->get(); // create an input server request - $req = new ServerRequest($serverParams); + $req = new ServerRequest("GET", "/", [], null, "1.1", $serverParams); // create the expected output $exp = $req; foreach ($expAttr as $key => $value) { @@ -156,7 +155,7 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { return $origin; }); $headers = isset($origin) ? ['Origin' => $origin] : []; - $req = new Request("", "GET", "php://memory", $headers); + $req = new Request("GET", "", $headers); $act = $rMock->get()->corsNegotiate($req, $allowed, $denied); $this->assertSame($exp, $act); } @@ -189,7 +188,7 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { /** @dataProvider provideCorsHeaders */ public function testAddCorsHeaders(string $reqMethod, array $reqHeaders, array $resHeaders, array $expHeaders): void { $r = new REST(); - $req = new Request("", $reqMethod, "php://memory", $reqHeaders); + $req = new Request($reqMethod, "php://memory", $reqHeaders); $res = HTTP::respEmpty(204, $resHeaders); $exp = HTTP::respEmpty(204, $expHeaders); $act = $r->corsApply($res, $req); @@ -277,12 +276,12 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { [HTTP::respEmpty(204, ['Allow' => ["PUT, DELETE", "OPTIONS"]]), HTTP::respEmpty(204, ['Allow' => "PUT, DELETE, OPTIONS"])], [HTTP::respEmpty(204, ['Allow' => "HEAD,GET"]), HTTP::respEmpty(204, ['Allow' => "HEAD, GET, OPTIONS"])], [HTTP::respEmpty(204, ['Allow' => "GET"]), HTTP::respEmpty(204, ['Allow' => "GET, HEAD, OPTIONS"])], - [new TextResponse("ook", 200), new TextResponse("ook", 200, ['Content-Length' => "3"])], - [new TextResponse("", 200), new TextResponse("", 200, ['Content-Length' => "0"])], - [new TextResponse("ook", 404), new TextResponse("ook", 404, ['Content-Length' => "3"])], - [new TextResponse("", 404), new TextResponse("", 404)], - [new Response($stream, 200), new Response($stream, 200, ['Content-Length' => "3"]), new Request("", "GET")], - [new Response($stream, 200), HTTP::respEmpty(200, ['Content-Length' => "3"]), new Request("", "HEAD")], + [HTTP::respText("ook", 200), HTTP::respText("ook", 200, ['Content-Length' => "3"])], + [HTTP::respText("", 200), HTTP::respText("", 200, ['Content-Length' => "0"])], + [HTTP::respText("ook", 404), HTTP::respText("ook", 404, ['Content-Length' => "3"])], + [HTTP::respText("", 404), HTTP::respText("", 404)], + [new Response(200, [], $stream), new Response(200, ['Content-Length' => "3"], $stream), new Request("", "GET")], + [new Response(200, [], $stream), HTTP::respEmpty(200, ['Content-Length' => "3"]), new Request("", "HEAD")], ]; } @@ -318,13 +317,13 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { public function provideMockRequests(): iterable { return [ - [new ServerRequest([], [], "/index.php/apps/news/api/v1-2/feeds", "GET"), "GET", true, NCN::class, "/feeds"], - [new ServerRequest([], [], "/index.php/apps/news/api/v1-2/feeds", "HEAD"), "GET", true, NCN::class, "/feeds"], - [new ServerRequest([], [], "/index.php/apps/news/api/v1-2/feeds", "get"), "GET", true, NCN::class, "/feeds"], - [new ServerRequest([], [], "/index.php/apps/news/api/v1-2/feeds", "head"), "GET", true, NCN::class, "/feeds"], - [new ServerRequest([], [], "/tt-rss/api/", "POST"), "POST", true, TTRSS::class, "/"], - [new ServerRequest([], [], "/no/such/api/", "HEAD"), "GET", false], - [new ServerRequest([], [], "/no/such/api/", "GET"), "GET", false], + [new ServerRequest("GET", "/index.php/apps/news/api/v1-2/feeds"), "GET", true, NCN::class, "/feeds"], + [new ServerRequest("GET", "/index.php/apps/news/api/v1-2/feeds"), "GET", true, NCN::class, "/feeds"], + [new ServerRequest("get", "/index.php/apps/news/api/v1-2/feeds"), "GET", true, NCN::class, "/feeds"], + [new ServerRequest("head", "/index.php/apps/news/api/v1-2/feeds"), "GET", true, NCN::class, "/feeds"], + [new ServerRequest("POST", "/tt-rss/api/"), "POST", true, TTRSS::class, "/"], + [new ServerRequest("HEAD", "/no/such/api/"), "GET", false], + [new ServerRequest("GET", "/no/such/api/"), "GET", false], ]; } } From 459e44e04159a67898f28fb9bd4ca1353aa4743a Mon Sep 17 00:00:00 2001 From: "J. King" Date: Sat, 6 Aug 2022 16:03:50 -0400 Subject: [PATCH 10/16] Address remaining errors Still many failures to fix --- lib/REST/Miniflux/ErrorResponse.php | 19 -- lib/REST/Miniflux/V1.php | 132 ++++----- tests/cases/REST/Fever/TestAPI.php | 3 +- .../cases/REST/Miniflux/TestErrorResponse.php | 22 -- tests/cases/REST/Miniflux/TestStatus.php | 5 +- tests/cases/REST/Miniflux/TestV1.php | 255 +++++++++--------- tests/cases/REST/TestREST.php | 6 +- tests/cases/REST/TinyTinyRSS/TestAPI.php | 32 +-- tests/lib/AbstractTest.php | 19 +- tests/phpunit.dist.xml | 1 - 10 files changed, 233 insertions(+), 261 deletions(-) delete mode 100644 lib/REST/Miniflux/ErrorResponse.php delete mode 100644 tests/cases/REST/Miniflux/TestErrorResponse.php diff --git a/lib/REST/Miniflux/ErrorResponse.php b/lib/REST/Miniflux/ErrorResponse.php deleted file mode 100644 index 1cf467ee..00000000 --- a/lib/REST/Miniflux/ErrorResponse.php +++ /dev/null @@ -1,19 +0,0 @@ - Arsse::$lang->msg("API.Miniflux.Error.".$msg, $data)]; - parent::__construct($data, $status, $headers, $encodingOptions); - } -} diff --git a/lib/REST/Miniflux/V1.php b/lib/REST/Miniflux/V1.php index 7ff9df24..b1fb512f 100644 --- a/lib/REST/Miniflux/V1.php +++ b/lib/REST/Miniflux/V1.php @@ -212,6 +212,14 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { public function __construct() { } + + public static function respError($data, int $status = 400, array $headers = []): ResponseInterface { + assert(isset(Arsse::$lang) && Arsse::$lang instanceof \JKingWeb\Arsse\Lang, new \Exception("Language database must be initialized before use")); + $data = (array) $data; + $msg = array_shift($data); + $data = ["error_message" => Arsse::$lang->msg("API.Miniflux.Error.".$msg, $data)]; + return HTTP::respJson($data, $status, $headers); + } protected function authenticate(ServerRequestInterface $req): bool { // first check any tokens; this is what Miniflux does @@ -245,7 +253,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } // try to authenticate if (!$this->authenticate($req)) { - return new ErrorResponse("401", 401); + return self::respError("401", 401); } $func = $this->chooseCall($target, $method); if ($func instanceof ResponseInterface) { @@ -254,7 +262,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { [$func, $reqAdmin, $reqPath, $reqBody, $reqQuery, $reqFields] = $func; } if ($reqAdmin && !$this->isAdmin()) { - return new ErrorResponse("403", 403); + return self::respError("403", 403); } $args = []; if ($reqPath) { @@ -269,7 +277,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { $data = @json_decode($data, true); if (json_last_error() !== \JSON_ERROR_NONE) { // if the body could not be parsed as JSON, return "400 Bad Request" - return new ErrorResponse(["InvalidBodyJSON", json_last_error_msg()], 400); + return self::respError(["InvalidBodyJSON", json_last_error_msg()], 400); } } else { $data = []; @@ -344,20 +352,20 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { if (!isset($body[$k])) { $body[$k] = null; } elseif (gettype($body[$k]) !== $t) { - return new ErrorResponse(["InvalidInputType", 'field' => $k, 'expected' => $t, 'actual' => gettype($body[$k])], 422); + return self::respError(["InvalidInputType", 'field' => $k, 'expected' => $t, 'actual' => gettype($body[$k])], 422); } elseif ( (in_array($k, ["keeplist_rules", "blocklist_rules"]) && !Rule::validate($body[$k])) || (in_array($k, ["url", "feed_url"]) && !URL::absolute($body[$k])) || ($k === "category_id" && $body[$k] < 1) || ($k === "status" && !in_array($body[$k], ["read", "unread", "removed"])) ) { - return new ErrorResponse(["InvalidInputValue", 'field' => $k], 422); + return self::respError(["InvalidInputValue", 'field' => $k], 422); } elseif ($k === "entry_ids") { foreach ($body[$k] as $v) { if (gettype($v) !== "integer") { - return new ErrorResponse(["InvalidInputType", 'field' => $k, 'expected' => "integer", 'actual' => gettype($v)], 422); + return self::respError(["InvalidInputType", 'field' => $k, 'expected' => "integer", 'actual' => gettype($v)], 422); } elseif ($v < 1) { - return new ErrorResponse(["InvalidInputValue", 'field' => $k], 422); + return self::respError(["InvalidInputValue", 'field' => $k], 422); } } } @@ -369,16 +377,16 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { $body[$k] = null; } elseif ($k === "entry_sorting_direction") { if (!in_array($body[$k], ["asc", "desc"])) { - return new ErrorResponse(["InvalidInputValue", 'field' => $k], 422); + return self::respError(["InvalidInputValue", 'field' => $k], 422); } } elseif (gettype($body[$k]) !== $t) { - return new ErrorResponse(["InvalidInputType", 'field' => $k, 'expected' => $t, 'actual' => gettype($body[$k])], 422); + return self::respError(["InvalidInputType", 'field' => $k, 'expected' => $t, 'actual' => gettype($body[$k])], 422); } } // check for any missing required values foreach ($req as $k) { if (!isset($body[$k]) || (is_array($body[$k]) && !$body[$k])) { - return new ErrorResponse(["MissingInputValue", 'field' => $k], 422); + return self::respError(["MissingInputValue", 'field' => $k], 422); } } return $body; @@ -407,7 +415,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { if ($seen[$k] && !$a) { // if the key has already been seen and it's not an array field, bail // NOTE: Miniflux itself simply ignores duplicates entirely - return new ErrorResponse(["DuplicateInputValue", 'field' => $k], 400); + return self::respError(["DuplicateInputValue", 'field' => $k], 400); } $seen[$k] = true; if ($k === "starred") { @@ -423,7 +431,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { $out[$k] = V::normalize($v, $t + V::M_STRICT, "unix"); } } catch (ExceptionType $e) { - return new ErrorResponse(["InvalidInputValue", 'field' => $k], 400); + return self::respError(["InvalidInputValue", 'field' => $k], 400); } // perform additional validation if ( @@ -433,7 +441,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { || ($k === "order" && !in_array($v, ["id", "status", "published_at", "category_title", "category_id"])) || ($k === "status" && !in_array($v, ["read", "unread", "removed"])) ) { - return new ErrorResponse(["InvalidInputValue", 'field' => $k], 400); + return self::respError(["InvalidInputValue", 'field' => $k], 400); } } return $out; @@ -525,7 +533,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { 10507 => "Fetch401", 10521 => "Fetch404", ][$e->getCode()] ?? "FetchOther"; - return new ErrorResponse($msg, 502); + return self::respError($msg, 502); } $out = []; foreach ($list as $url) { @@ -544,7 +552,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { try { return HTTP::respJson($this->listUsers([$path[1]], true)[0] ?? new \stdClass); } catch (UserException $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } } @@ -553,7 +561,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { $user = Arsse::$user->lookup((int) $path[1]); return HTTP::respJson($this->listUsers([$user], true)[0] ?? new \stdClass); } catch (UserException $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } } @@ -570,13 +578,13 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (UserException $e) { switch ($e->getCode()) { case 10403: - return new ErrorResponse(["DuplicateUser", 'user' => $data['username']], 409); + return self::respError(["DuplicateUser", 'user' => $data['username']], 409); case 10441: - return new ErrorResponse(["InvalidInputValue", 'field' => "timezone"], 422); + return self::respError(["InvalidInputValue", 'field' => "timezone"], 422); case 10443: - return new ErrorResponse(["InvalidInputValue", 'field' => "entries_per_page"], 422); + return self::respError(["InvalidInputValue", 'field' => "entries_per_page"], 422); case 10444: - return new ErrorResponse(["InvalidInputValue", 'field' => "username"], 422); + return self::respError(["InvalidInputValue", 'field' => "username"], 422); } throw $e; // @codeCoverageIgnore } @@ -589,16 +597,16 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { if (((int) $path[1]) === $user['num']) { if ($data['is_admin'] && !$user['admin']) { // non-admins should not be able to set themselves as admin - return new ErrorResponse("InvalidElevation", 403); + return self::respError("InvalidElevation", 403); } $user = Arsse::$user->id; } elseif (!$user['admin']) { - return new ErrorResponse("403", 403); + return self::respError("403", 403); } else { try { $user = Arsse::$user->lookup((int) $path[1]); } catch (ExceptionConflict $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } } // make any requested changes @@ -616,13 +624,13 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (UserException $e) { switch ($e->getCode()) { case 10403: - return new ErrorResponse(["DuplicateUser", 'user' => $data['username']], 409); + return self::respError(["DuplicateUser", 'user' => $data['username']], 409); case 10441: - return new ErrorResponse(["InvalidInputValue", 'field' => "timezone"], 422); + return self::respError(["InvalidInputValue", 'field' => "timezone"], 422); case 10443: - return new ErrorResponse(["InvalidInputValue", 'field' => "entries_per_page"], 422); + return self::respError(["InvalidInputValue", 'field' => "entries_per_page"], 422); case 10444: - return new ErrorResponse(["InvalidInputValue", 'field' => "username"], 422); + return self::respError(["InvalidInputValue", 'field' => "username"], 422); } throw $e; // @codeCoverageIgnore } @@ -633,7 +641,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { try { Arsse::$user->remove(Arsse::$user->lookup((int) $path[1])); } catch (ExceptionConflict $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } return HTTP::respEmpty(204); } @@ -673,9 +681,9 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { $id = Arsse::$db->folderAdd(Arsse::$user->id, ['name' => (string) $data['title']]); } catch (ExceptionInput $e) { if ($e->getCode() === 10236) { - return new ErrorResponse(["DuplicateCategory", 'title' => $data['title']], 409); + return self::respError(["DuplicateCategory", 'title' => $data['title']], 409); } else { - return new ErrorResponse(["InvalidCategory", 'title' => $data['title']], 422); + return self::respError(["InvalidCategory", 'title' => $data['title']], 422); } } $meta = Arsse::$user->propertiesGet(Arsse::$user->id, false); @@ -698,11 +706,11 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } } catch (ExceptionInput $e) { if ($e->getCode() === 10236) { - return new ErrorResponse(["DuplicateCategory", 'title' => $title], 409); + return self::respError(["DuplicateCategory", 'title' => $title], 409); } elseif (in_array($e->getCode(), [10237, 10239])) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } else { - return new ErrorResponse(["InvalidCategory", 'title' => $title], 422); + return self::respError(["InvalidCategory", 'title' => $title], 422); } } $meta = Arsse::$user->propertiesGet(Arsse::$user->id, false); @@ -724,7 +732,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { $tr->commit(); } } catch (ExceptionInput $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } return HTTP::respEmpty(204); } @@ -788,7 +796,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } } catch (ExceptionInput $e) { // the folder does not exist - return new ErrorResponse("404", 404); + return self::respError("404", 404); } return HTTP::respJson($out); } @@ -800,7 +808,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { $sub = Arsse::$db->subscriptionPropertiesGet(Arsse::$user->id, (int) $path[1]); return HTTP::respJson($this->transformFeed($sub, $meta['num'], $meta['root'], $meta['tz'])); } catch (ExceptionInput $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } } @@ -823,13 +831,13 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { 10521 => "Fetch404", 10522 => "FetchFormat", ][$e->getCode()] ?? "FetchOther"; - return new ErrorResponse($msg, 502); + return self::respError($msg, 502); } catch (ExceptionInput $e) { switch ($e->getCode()) { case 10235: - return new ErrorResponse("MissingCategory", 422); + return self::respError("MissingCategory", 422); case 10236: - return new ErrorResponse("DuplicateFeed", 409); + return self::respError("DuplicateFeed", 409); } } return HTTP::respJson(['feed_id' => $id], 201); @@ -851,11 +859,11 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { switch ($e->getCode()) { case 10231: case 10232: - return new ErrorResponse("InvalidTitle", 422); + return self::respError("InvalidTitle", 422); case 10235: - return new ErrorResponse("MissingCategory", 422); + return self::respError("MissingCategory", 422); case 10239: - return new ErrorResponse("404", 404); + return self::respError("404", 404); } } return $this->getFeed($path)->withStatus(201); @@ -866,7 +874,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->subscriptionRemove(Arsse::$user->id, (int) $path[1]); return HTTP::respEmpty(204); } catch (ExceptionInput $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } } @@ -874,10 +882,10 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { try { $icon = Arsse::$db->subscriptionIcon(Arsse::$user->id, (int) $path[1]); } catch (ExceptionInput $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } if (!$icon || !$icon['type'] || !$icon['data']) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } return HTTP::respJson([ 'id' => (int) $icon['id'], @@ -1038,7 +1046,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { try { return HTTP::respJson($this->listEntries($query, new Context)); } catch (ExceptionInput $e) { - return new ErrorResponse("MissingCategory", 400); + return self::respError("MissingCategory", 400); } } @@ -1048,7 +1056,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { return HTTP::respJson($this->listEntries($query, $c)); } catch (ExceptionInput $e) { // FIXME: this should differentiate between a missing feed and a missing category, but doesn't - return new ErrorResponse("404", 404); + return self::respError("404", 404); } } @@ -1057,7 +1065,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { try { return HTTP::respJson($this->listEntries($query, new Context)); } catch (ExceptionInput $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } } @@ -1065,7 +1073,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { try { return HTTP::respJson($this->findEntry((int) $path[1])); } catch (ExceptionInput $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } } @@ -1074,7 +1082,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { try { return HTTP::respJson($this->findEntry((int) $path[3], $c)); } catch (ExceptionInput $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } } @@ -1088,7 +1096,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { try { return HTTP::respJson($this->findEntry((int) $path[3], $c)); } catch (ExceptionInput $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } } @@ -1113,7 +1121,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { // this function is restricted to the logged-in user $user = Arsse::$user->propertiesGet(Arsse::$user->id, false); if (((int) $path[1]) !== $user['num']) { - return new ErrorResponse("403", 403); + return self::respError("403", 403); } $this->massRead(new Context); return HTTP::respEmpty(204); @@ -1123,7 +1131,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { try { $this->massRead((new Context)->subscription((int) $path[1])); } catch (ExceptionInput $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } return HTTP::respEmpty(204); } @@ -1140,7 +1148,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { try { $this->massRead($c); } catch (ExceptionInput $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } return HTTP::respEmpty(204); } @@ -1158,7 +1166,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } $tr->commit(); } catch (ExceptionInput $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } return HTTP::respEmpty(204); } @@ -1168,7 +1176,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { try { Arsse::$db->subscriptionPropertiesGet(Arsse::$user->id, (int) $path[1]); } catch (ExceptionInput $e) { - return new ErrorResponse("404", 404); + return self::respError("404", 404); } return HTTP::respEmpty(204); } @@ -1185,18 +1193,18 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ImportException $e) { switch ($e->getCode()) { case 10611: - return new ErrorResponse("InvalidBodyXML", 400); + return self::respError("InvalidBodyXML", 400); case 10612: - return new ErrorResponse("InvalidBodyOPML", 422); + return self::respError("InvalidBodyOPML", 422); case 10613: - return new ErrorResponse("InvalidImportCategory", 422); + return self::respError("InvalidImportCategory", 422); case 10614: - return new ErrorResponse("DuplicateImportCategory", 422); + return self::respError("DuplicateImportCategory", 422); case 10615: - return new ErrorResponse("InvalidImportLabel", 422); + return self::respError("InvalidImportLabel", 422); } } catch (FeedException $e) { - return new ErrorResponse(["FailedImportFeed", 'url' => $e->getParams()['url'], 'code' => $e->getCode()], 502); + return self::respError(["FailedImportFeed", 'url' => $e->getParams()['url'], 'code' => $e->getCode()], 502); } return HTTP::respJson(['message' => Arsse::$lang->msg("API.Miniflux.ImportSuccess")]); } diff --git a/tests/cases/REST/Fever/TestAPI.php b/tests/cases/REST/Fever/TestAPI.php index 2f624da1..ff809647 100644 --- a/tests/cases/REST/Fever/TestAPI.php +++ b/tests/cases/REST/Fever/TestAPI.php @@ -16,7 +16,6 @@ use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\Db\Transaction; use JKingWeb\Arsse\REST\Fever\API; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\XmlResponse; /** @covers \JKingWeb\Arsse\REST\Fever\API */ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { @@ -472,7 +471,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { 'items' => $this->articles['rest'], 'total_items' => 1024, ]); - $exp = new XmlResponse("1018Article title 1<p>Article content 1</p>http://example.com/1009466848001028Article title 2<p>Article content 2</p>http://example.com/2019467712001039Article title 3<p>Article content 3</p>http://example.com/3109468576001049Article title 4<p>Article content 4</p>http://example.com/41194694400010510Article title 5<p>Article content 5</p>http://example.com/5009470304001024"); + $exp = HTTP::respXml("1018Article title 1<p>Article content 1</p>http://example.com/1009466848001028Article title 2<p>Article content 2</p>http://example.com/2019467712001039Article title 3<p>Article content 3</p>http://example.com/3109468576001049Article title 4<p>Article content 4</p>http://example.com/41194694400010510Article title 5<p>Article content 5</p>http://example.com/5009470304001024"); $this->assertMessage($exp, $this->req("api=xml")); } diff --git a/tests/cases/REST/Miniflux/TestErrorResponse.php b/tests/cases/REST/Miniflux/TestErrorResponse.php deleted file mode 100644 index 5852b4d0..00000000 --- a/tests/cases/REST/Miniflux/TestErrorResponse.php +++ /dev/null @@ -1,22 +0,0 @@ -assertSame('{"error_message":"Access Unauthorized"}', (string) $act->getBody()); - } - - public function testCreateVariableResponse(): void { - $act = new ErrorResponse(["InvalidBodyJSON", "Doh!"], 401); - $this->assertSame('{"error_message":"Invalid JSON payload: Doh!"}', (string) $act->getBody()); - } -} diff --git a/tests/cases/REST/Miniflux/TestStatus.php b/tests/cases/REST/Miniflux/TestStatus.php index cf573e3e..4975d4af 100644 --- a/tests/cases/REST/Miniflux/TestStatus.php +++ b/tests/cases/REST/Miniflux/TestStatus.php @@ -10,7 +10,6 @@ use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\REST\Miniflux\Status; use JKingWeb\Arsse\REST\Miniflux\V1; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\TextResponse; /** @covers \JKingWeb\Arsse\REST\Miniflux\Status */ class TestStatus extends \JKingWeb\Arsse\Test\AbstractTest { @@ -22,10 +21,10 @@ class TestStatus extends \JKingWeb\Arsse\Test\AbstractTest { public function provideRequests(): iterable { return [ - ["/version", "GET", new TextResponse(V1::VERSION)], + ["/version", "GET", HTTP::respText(V1::VERSION)], ["/version", "POST", HTTP::respEmpty(405, ['Allow' => "HEAD, GET"])], ["/version", "OPTIONS", HTTP::respEmpty(204, ['Allow' => "HEAD, GET"])], - ["/healthcheck", "GET", new TextResponse("OK")], + ["/healthcheck", "GET", HTTP::respText("OK")], ["/healthcheck", "POST", HTTP::respEmpty(405, ['Allow' => "HEAD, GET"])], ["/healthcheck", "OPTIONS", HTTP::respEmpty(204, ['Allow' => "HEAD, GET"])], ["/version/", "GET", HTTP::respEmpty(404)], diff --git a/tests/cases/REST/Miniflux/TestV1.php b/tests/cases/REST/Miniflux/TestV1.php index b1dec747..ca4ae1fa 100644 --- a/tests/cases/REST/Miniflux/TestV1.php +++ b/tests/cases/REST/Miniflux/TestV1.php @@ -26,7 +26,6 @@ use JKingWeb\Arsse\User\ExceptionConflict; use JKingWeb\Arsse\User\ExceptionInput as UserExceptionInput; use JKingWeb\Arsse\Test\Result; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\TextResponse; /** @covers \JKingWeb\Arsse\REST\Miniflux\V1 */ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { @@ -101,7 +100,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { /** @dataProvider provideAuthResponses */ public function testAuthenticateAUser($token, bool $auth, bool $success): void { - $exp = $success ? HTTP::respEmpty(404) : new ErrorResponse("401", 401); + $exp = $success ? HTTP::respEmpty(404) : V1::respError("401", 401); $user = "john.doe@example.com"; if ($token !== null) { $headers = ['X-Auth-Token' => $token]; @@ -165,7 +164,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { } public function testRejectBadlyTypedData(): void { - $exp = new ErrorResponse(["InvalidInputType", 'field' => "url", 'expected' => "string", 'actual' => "integer"], 422); + $exp = V1::respError(["InvalidInputType", 'field' => "url", 'expected' => "string", 'actual' => "integer"], 422); $this->assertMessage($exp, $this->req("POST", "/discover", ['url' => 2112])); } @@ -183,10 +182,10 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { return [ ["http://localhost:8000/Feed/Discovery/Valid", HTTP::respJson($discovered)], ["http://localhost:8000/Feed/Discovery/Invalid", HTTP::respJson([])], - ["http://localhost:8000/Feed/Discovery/Missing", new ErrorResponse("Fetch404", 502)], - [1, new ErrorResponse(["InvalidInputType", 'field' => "url", 'expected' => "string", 'actual' => "integer"], 422)], - ["Not a URL", new ErrorResponse(["InvalidInputValue", 'field' => "url"], 422)], - [null, new ErrorResponse(["MissingInputValue", 'field' => "url"], 422)], + ["http://localhost:8000/Feed/Discovery/Missing", V1::respError("Fetch404", 502)], + [1, V1::respError(["InvalidInputType", 'field' => "url", 'expected' => "string", 'actual' => "integer"], 422)], + ["Not a URL", V1::respError(["InvalidInputValue", 'field' => "url"], 422)], + [null, V1::respError(["MissingInputValue", 'field' => "url"], 422)], ]; } @@ -231,16 +230,16 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { [true, "/users/1", HTTP::respJson(self::USERS[0])], [true, "/users/jane.doe@example.com", HTTP::respJson(self::USERS[1])], [true, "/users/2", HTTP::respJson(self::USERS[1])], - [true, "/users/jack.doe@example.com", new ErrorResponse("404", 404)], - [true, "/users/47", new ErrorResponse("404", 404)], - [false, "/users", new ErrorResponse("403", 403)], + [true, "/users/jack.doe@example.com", V1::respError("404", 404)], + [true, "/users/47", V1::respError("404", 404)], + [false, "/users", V1::respError("403", 403)], [false, "/me", HTTP::respJson(self::USERS[1])], - [false, "/users/john.doe@example.com", new ErrorResponse("403", 403)], - [false, "/users/1", new ErrorResponse("403", 403)], - [false, "/users/jane.doe@example.com", new ErrorResponse("403", 403)], - [false, "/users/2", new ErrorResponse("403", 403)], - [false, "/users/jack.doe@example.com", new ErrorResponse("403", 403)], - [false, "/users/47", new ErrorResponse("403", 403)], + [false, "/users/john.doe@example.com", V1::respError("403", 403)], + [false, "/users/1", V1::respError("403", 403)], + [false, "/users/jane.doe@example.com", V1::respError("403", 403)], + [false, "/users/2", V1::respError("403", 403)], + [false, "/users/jack.doe@example.com", V1::respError("403", 403)], + [false, "/users/47", V1::respError("403", 403)], ]; } @@ -305,21 +304,21 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { $resp1 = array_merge(self::USERS[1], ['username' => "john.doe@example.com"]); $resp2 = array_merge(self::USERS[1], ['id' => 1, 'is_admin' => true]); return [ - [false, "/users/1", ['is_admin' => 0], null, null, null, null, null, null, new ErrorResponse(["InvalidInputType", 'field' => "is_admin", 'expected' => "boolean", 'actual' => "integer"], 422)], - [false, "/users/1", ['entry_sorting_direction' => "bad"], null, null, null, null, null, null, new ErrorResponse(["InvalidInputValue", 'field' => "entry_sorting_direction"], 422)], - [false, "/users/1", ['theme' => "stark"], null, null, null, null, null, null, new ErrorResponse("403", 403)], - [false, "/users/2", ['is_admin' => true], null, null, null, null, null, null, new ErrorResponse("InvalidElevation", 403)], + [false, "/users/1", ['is_admin' => 0], null, null, null, null, null, null, V1::respError(["InvalidInputType", 'field' => "is_admin", 'expected' => "boolean", 'actual' => "integer"], 422)], + [false, "/users/1", ['entry_sorting_direction' => "bad"], null, null, null, null, null, null, V1::respError(["InvalidInputValue", 'field' => "entry_sorting_direction"], 422)], + [false, "/users/1", ['theme' => "stark"], null, null, null, null, null, null, V1::respError("403", 403)], + [false, "/users/2", ['is_admin' => true], null, null, null, null, null, null, V1::respError("InvalidElevation", 403)], [false, "/users/2", ['language' => "fr_CA"], null, null, null, null, ['lang' => "fr_CA"], $out1, HTTP::respJson($resp1, 201)], [false, "/users/2", ['entry_sorting_direction' => "asc"], null, null, null, null, ['sort_asc' => true], $out1, HTTP::respJson($resp1, 201)], [false, "/users/2", ['entry_sorting_direction' => "desc"], null, null, null, null, ['sort_asc' => false], $out1, HTTP::respJson($resp1, 201)], - [false, "/users/2", ['entries_per_page' => -1], null, null, null, null, ['page_size' => -1], new UserExceptionInput("invalidNonZeroInteger"), new ErrorResponse(["InvalidInputValue", 'field' => "entries_per_page"], 422)], - [false, "/users/2", ['timezone' => "Ook"], null, null, null, null, ['tz' => "Ook"], new UserExceptionInput("invalidTimezone"), new ErrorResponse(["InvalidInputValue", 'field' => "timezone"], 422)], - [false, "/users/2", ['username' => "j:k"], "j:k", new UserExceptionInput("invalidUsername"), null, null, null, null, new ErrorResponse(["InvalidInputValue", 'field' => "username"], 422)], - [false, "/users/2", ['username' => "ook"], "ook", new ExceptionConflict("alreadyExists"), null, null, null, null, new ErrorResponse(["DuplicateUser", 'user' => "ook"], 409)], + [false, "/users/2", ['entries_per_page' => -1], null, null, null, null, ['page_size' => -1], new UserExceptionInput("invalidNonZeroInteger"), V1::respError(["InvalidInputValue", 'field' => "entries_per_page"], 422)], + [false, "/users/2", ['timezone' => "Ook"], null, null, null, null, ['tz' => "Ook"], new UserExceptionInput("invalidTimezone"), V1::respError(["InvalidInputValue", 'field' => "timezone"], 422)], + [false, "/users/2", ['username' => "j:k"], "j:k", new UserExceptionInput("invalidUsername"), null, null, null, null, V1::respError(["InvalidInputValue", 'field' => "username"], 422)], + [false, "/users/2", ['username' => "ook"], "ook", new ExceptionConflict("alreadyExists"), null, null, null, null, V1::respError(["DuplicateUser", 'user' => "ook"], 409)], [false, "/users/2", ['password' => "ook"], null, null, "ook", "ook", null, null, HTTP::respJson(array_merge($resp1, ['password' => "ook"]), 201)], [false, "/users/2", ['username' => "ook", 'password' => "ook"], "ook", true, "ook", "ook", null, null, HTTP::respJson(array_merge($resp1, ['username' => "ook", 'password' => "ook"]), 201)], [true, "/users/1", ['theme' => "stark"], null, null, null, null, ['theme' => "stark"], $out2, HTTP::respJson($resp2, 201)], - [true, "/users/3", ['theme' => "stark"], null, null, null, null, null, null, new ErrorResponse("404", 404)], + [true, "/users/3", ['theme' => "stark"], null, null, null, null, null, null, V1::respError("404", 404)], ]; } @@ -360,18 +359,18 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideUserAdditions(): iterable { $resp1 = array_merge(self::USERS[1], ['username' => "ook", 'password' => "eek"]); return [ - [[], null, null, null, null, new ErrorResponse(["MissingInputValue", 'field' => "username"], 422)], - [['username' => "ook"], null, null, null, null, new ErrorResponse(["MissingInputValue", 'field' => "password"], 422)], - [['username' => "ook", 'password' => "eek"], ["ook", "eek"], new ExceptionConflict("alreadyExists"), null, null, new ErrorResponse(["DuplicateUser", 'user' => "ook"], 409)], - [['username' => "j:k", 'password' => "eek"], ["j:k", "eek"], new UserExceptionInput("invalidUsername"), null, null, new ErrorResponse(["InvalidInputValue", 'field' => "username"], 422)], - [['username' => "ook", 'password' => "eek", 'timezone' => "ook"], ["ook", "eek"], "eek", ['tz' => "ook"], new UserExceptionInput("invalidTimezone"), new ErrorResponse(["InvalidInputValue", 'field' => "timezone"], 422)], - [['username' => "ook", 'password' => "eek", 'entries_per_page' => -1], ["ook", "eek"], "eek", ['page_size' => -1], new UserExceptionInput("invalidNonZeroInteger"), new ErrorResponse(["InvalidInputValue", 'field' => "entries_per_page"], 422)], + [[], null, null, null, null, V1::respError(["MissingInputValue", 'field' => "username"], 422)], + [['username' => "ook"], null, null, null, null, V1::respError(["MissingInputValue", 'field' => "password"], 422)], + [['username' => "ook", 'password' => "eek"], ["ook", "eek"], new ExceptionConflict("alreadyExists"), null, null, V1::respError(["DuplicateUser", 'user' => "ook"], 409)], + [['username' => "j:k", 'password' => "eek"], ["j:k", "eek"], new UserExceptionInput("invalidUsername"), null, null, V1::respError(["InvalidInputValue", 'field' => "username"], 422)], + [['username' => "ook", 'password' => "eek", 'timezone' => "ook"], ["ook", "eek"], "eek", ['tz' => "ook"], new UserExceptionInput("invalidTimezone"), V1::respError(["InvalidInputValue", 'field' => "timezone"], 422)], + [['username' => "ook", 'password' => "eek", 'entries_per_page' => -1], ["ook", "eek"], "eek", ['page_size' => -1], new UserExceptionInput("invalidNonZeroInteger"), V1::respError(["InvalidInputValue", 'field' => "entries_per_page"], 422)], [['username' => "ook", 'password' => "eek", 'theme' => "default"], ["ook", "eek"], "eek", ['theme' => "default"], ['theme' => "default"], HTTP::respJson($resp1, 201)], ]; } public function testAddAUserWithoutAuthority(): void { - $this->assertMessage(new ErrorResponse("403", 403), $this->req("POST", "/users", [])); + $this->assertMessage(V1::respError("403", 403), $this->req("POST", "/users", [])); } public function testDeleteAUser(): void { @@ -391,13 +390,13 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { Arsse::$user->method("remove")->willReturn(true); Arsse::$user->expects($this->exactly(1))->method("lookup")->with(2112); Arsse::$user->expects($this->exactly(0))->method("remove"); - $this->assertMessage(new ErrorResponse("404", 404), $this->req("DELETE", "/users/2112")); + $this->assertMessage(V1::respError("404", 404), $this->req("DELETE", "/users/2112")); } public function testDeleteAUserWithoutAuthority(): void { Arsse::$user->expects($this->exactly(0))->method("lookup"); Arsse::$user->expects($this->exactly(0))->method("remove"); - $this->assertMessage(new ErrorResponse("403", 403), $this->req("DELETE", "/users/2112")); + $this->assertMessage(V1::respError("403", 403), $this->req("DELETE", "/users/2112")); } public function testListCategories(): void { @@ -440,11 +439,11 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideCategoryAdditions(): iterable { return [ ["New", HTTP::respJson(['id' => 2112, 'title' => "New", 'user_id' => 42], 201)], - ["Duplicate", new ErrorResponse(["DuplicateCategory", 'title' => "Duplicate"], 409)], - ["", new ErrorResponse(["InvalidCategory", 'title' => ""], 422)], - [" ", new ErrorResponse(["InvalidCategory", 'title' => " "], 422)], - [null, new ErrorResponse(["MissingInputValue", 'field' => "title"], 422)], - [false, new ErrorResponse(["InvalidInputType", 'field' => "title", 'actual' => "boolean", 'expected' => "string"], 422)], + ["Duplicate", V1::respError(["DuplicateCategory", 'title' => "Duplicate"], 409)], + ["", V1::respError(["InvalidCategory", 'title' => ""], 422)], + [" ", V1::respError(["InvalidCategory", 'title' => " "], 422)], + [null, V1::respError(["MissingInputValue", 'field' => "title"], 422)], + [false, V1::respError(["InvalidInputType", 'field' => "title", 'actual' => "boolean", 'expected' => "string"], 422)], ]; } @@ -465,19 +464,19 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideCategoryUpdates(): iterable { return [ - [3, "New", "subjectMissing", new ErrorResponse("404", 404)], + [3, "New", "subjectMissing", V1::respError("404", 404)], [2, "New", true, HTTP::respJson(['id' => 2, 'title' => "New", 'user_id' => 42], 201)], - [2, "Duplicate", "constraintViolation", new ErrorResponse(["DuplicateCategory", 'title' => "Duplicate"], 409)], - [2, "", "missing", new ErrorResponse(["InvalidCategory", 'title' => ""], 422)], - [2, " ", "whitespace", new ErrorResponse(["InvalidCategory", 'title' => " "], 422)], - [2, null, "missing", new ErrorResponse(["MissingInputValue", 'field' => "title"], 422)], - [2, false, "subjectMissing", new ErrorResponse(["InvalidInputType", 'field' => "title", 'actual' => "boolean", 'expected' => "string"], 422)], + [2, "Duplicate", "constraintViolation", V1::respError(["DuplicateCategory", 'title' => "Duplicate"], 409)], + [2, "", "missing", V1::respError(["InvalidCategory", 'title' => ""], 422)], + [2, " ", "whitespace", V1::respError(["InvalidCategory", 'title' => " "], 422)], + [2, null, "missing", V1::respError(["MissingInputValue", 'field' => "title"], 422)], + [2, false, "subjectMissing", V1::respError(["InvalidInputType", 'field' => "title", 'actual' => "boolean", 'expected' => "string"], 422)], [1, "New", true, HTTP::respJson(['id' => 1, 'title' => "New", 'user_id' => 42], 201)], [1, "Duplicate", "constraintViolation", HTTP::respJson(['id' => 1, 'title' => "Duplicate", 'user_id' => 42], 201)], // This is allowed because the name of the root folder is only a duplicate in circumstances where it is used - [1, "", "missing", new ErrorResponse(["InvalidCategory", 'title' => ""], 422)], - [1, " ", "whitespace", new ErrorResponse(["InvalidCategory", 'title' => " "], 422)], - [1, null, "missing", new ErrorResponse(["MissingInputValue", 'field' => "title"], 422)], - [1, false, false, new ErrorResponse(["InvalidInputType", 'field' => "title", 'actual' => "boolean", 'expected' => "string"], 422)], + [1, "", "missing", V1::respError(["InvalidCategory", 'title' => ""], 422)], + [1, " ", "whitespace", V1::respError(["InvalidCategory", 'title' => " "], 422)], + [1, null, "missing", V1::respError(["MissingInputValue", 'field' => "title"], 422)], + [1, false, false, V1::respError(["InvalidInputType", 'field' => "title", 'actual' => "boolean", 'expected' => "string"], 422)], ]; } @@ -485,7 +484,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->folderRemove->returns(true)->throws(new ExceptionInput("subjectMissing")); $this->assertMessage(HTTP::respEmpty(204), $this->req("DELETE", "/categories/2112")); $this->dbMock->folderRemove->calledWith("john.doe@example.com", 2111); - $this->assertMessage(new ErrorResponse("404", 404), $this->req("DELETE", "/categories/47")); + $this->assertMessage(V1::respError("404", 404), $this->req("DELETE", "/categories/47")); $this->dbMock->folderRemove->calledWith("john.doe@example.com", 46); } @@ -529,7 +528,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function testListFeedsOfAMissingCategory(): void { $this->dbMock->subscriptionList->throws(new ExceptionInput("idMissing")); - $exp = new ErrorResponse("404", 404); + $exp = V1::respError("404", 404); $this->assertMessage($exp, $this->req("GET", "/categories/2112/feeds")); $this->dbMock->subscriptionList->calledWith(Arsse::$user->id, 2111, true); } @@ -544,7 +543,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function testGetAMissingFeed(): void { $this->dbMock->subscriptionPropertiesGet->throws(new ExceptionInput("subjectMissing")); - $this->assertMessage(new ErrorResponse("404", 404), $this->req("GET", "/feeds/1")); + $this->assertMessage(V1::respError("404", 404), $this->req("GET", "/feeds/1")); $this->dbMock->subscriptionPropertiesGet->calledWith(Arsse::$user->id, 1); } @@ -610,29 +609,29 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideFeedCreations(): iterable { self::clearData(); return [ - [['category_id' => 1], null, null, null, null, new ErrorResponse(["MissingInputValue", 'field' => "feed_url"], 422)], - [['feed_url' => "http://example.com/"], null, null, null, null, new ErrorResponse(["MissingInputValue", 'field' => "category_id"], 422)], - [['feed_url' => "http://example.com/", 'category_id' => "1"], null, null, null, null, new ErrorResponse(["InvalidInputType", 'field' => "category_id", 'expected' => "integer", 'actual' => "string"], 422)], - [['feed_url' => "Not a URL", 'category_id' => 1], null, null, null, null, new ErrorResponse(["InvalidInputValue", 'field' => "feed_url"], 422)], - [['feed_url' => "http://example.com/", 'category_id' => 0], null, null, null, null, new ErrorResponse(["InvalidInputValue", 'field' => "category_id"], 422)], - [['feed_url' => "http://example.com/", 'category_id' => 1, 'keeplist_rules' => "["], null, null, null, null, new ErrorResponse(["InvalidInputValue", 'field' => "keeplist_rules"], 422)], - [['feed_url' => "http://example.com/", 'category_id' => 1, 'blocklist_rules' => "["], null, null, null, null, new ErrorResponse(["InvalidInputValue", 'field' => "blocklist_rules"], 422)], - [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("internalError"), null, null, null, new ErrorResponse("FetchOther", 502)], - [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("invalidCertificate"), null, null, null, new ErrorResponse("FetchOther", 502)], - [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("invalidUrl"), null, null, null, new ErrorResponse("Fetch404", 502)], - [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("maxRedirect"), null, null, null, new ErrorResponse("FetchOther", 502)], - [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("maxSize"), null, null, null, new ErrorResponse("FetchOther", 502)], - [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("timeout"), null, null, null, new ErrorResponse("FetchOther", 502)], - [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("forbidden"), null, null, null, new ErrorResponse("Fetch403", 502)], - [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("unauthorized"), null, null, null, new ErrorResponse("Fetch401", 502)], - [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("transmissionError"), null, null, null, new ErrorResponse("FetchOther", 502)], - [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("connectionFailed"), null, null, null, new ErrorResponse("FetchOther", 502)], - [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("malformedXml"), null, null, null, new ErrorResponse("FetchOther", 502)], - [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("xmlEntity"), null, null, null, new ErrorResponse("FetchOther", 502)], - [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("subscriptionNotFound"), null, null, null, new ErrorResponse("Fetch404", 502)], - [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("unsupportedFeedFormat"), null, null, null, new ErrorResponse("FetchFormat", 502)], - [['feed_url' => "http://example.com/", 'category_id' => 1], 2112, new ExceptionInput("constraintViolation"), null, null, new ErrorResponse("DuplicateFeed", 409)], - [['feed_url' => "http://example.com/", 'category_id' => 1], 2112, 44, new ExceptionInput("idMissing"), null, new ErrorResponse("MissingCategory", 422)], + [['category_id' => 1], null, null, null, null, V1::respError(["MissingInputValue", 'field' => "feed_url"], 422)], + [['feed_url' => "http://example.com/"], null, null, null, null, V1::respError(["MissingInputValue", 'field' => "category_id"], 422)], + [['feed_url' => "http://example.com/", 'category_id' => "1"], null, null, null, null, V1::respError(["InvalidInputType", 'field' => "category_id", 'expected' => "integer", 'actual' => "string"], 422)], + [['feed_url' => "Not a URL", 'category_id' => 1], null, null, null, null, V1::respError(["InvalidInputValue", 'field' => "feed_url"], 422)], + [['feed_url' => "http://example.com/", 'category_id' => 0], null, null, null, null, V1::respError(["InvalidInputValue", 'field' => "category_id"], 422)], + [['feed_url' => "http://example.com/", 'category_id' => 1, 'keeplist_rules' => "["], null, null, null, null, V1::respError(["InvalidInputValue", 'field' => "keeplist_rules"], 422)], + [['feed_url' => "http://example.com/", 'category_id' => 1, 'blocklist_rules' => "["], null, null, null, null, V1::respError(["InvalidInputValue", 'field' => "blocklist_rules"], 422)], + [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("internalError"), null, null, null, V1::respError("FetchOther", 502)], + [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("invalidCertificate"), null, null, null, V1::respError("FetchOther", 502)], + [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("invalidUrl"), null, null, null, V1::respError("Fetch404", 502)], + [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("maxRedirect"), null, null, null, V1::respError("FetchOther", 502)], + [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("maxSize"), null, null, null, V1::respError("FetchOther", 502)], + [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("timeout"), null, null, null, V1::respError("FetchOther", 502)], + [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("forbidden"), null, null, null, V1::respError("Fetch403", 502)], + [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("unauthorized"), null, null, null, V1::respError("Fetch401", 502)], + [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("transmissionError"), null, null, null, V1::respError("FetchOther", 502)], + [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("connectionFailed"), null, null, null, V1::respError("FetchOther", 502)], + [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("malformedXml"), null, null, null, V1::respError("FetchOther", 502)], + [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("xmlEntity"), null, null, null, V1::respError("FetchOther", 502)], + [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("subscriptionNotFound"), null, null, null, V1::respError("Fetch404", 502)], + [['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("unsupportedFeedFormat"), null, null, null, V1::respError("FetchFormat", 502)], + [['feed_url' => "http://example.com/", 'category_id' => 1], 2112, new ExceptionInput("constraintViolation"), null, null, V1::respError("DuplicateFeed", 409)], + [['feed_url' => "http://example.com/", 'category_id' => 1], 2112, 44, new ExceptionInput("idMissing"), null, V1::respError("MissingCategory", 422)], [['feed_url' => "http://example.com/", 'category_id' => 1], 2112, 44, true, null, HTTP::respJson(['feed_id' => 44], 201)], [['feed_url' => "http://example.com/", 'category_id' => 1, 'keeplist_rules' => "^A"], 2112, 44, true, true, HTTP::respJson(['feed_id' => 44], 201)], [['feed_url' => "http://example.com/", 'category_id' => 1, 'blocklist_rules' => "A"], 2112, 44, true, true, HTTP::respJson(['feed_id' => 44], 201)], @@ -657,11 +656,11 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { $success = HTTP::respJson(self::FEEDS_OUT[0], 201); return [ [[], [], true, $success], - [[], [], new ExceptionInput("subjectMissing"), new ErrorResponse("404", 404)], - [['title' => ""], ['title' => ""], new ExceptionInput("missing"), new ErrorResponse("InvalidTitle", 422)], - [['title' => " "], ['title' => " "], new ExceptionInput("whitespace"), new ErrorResponse("InvalidTitle", 422)], - [['title' => " "], ['title' => " "], new ExceptionInput("whitespace"), new ErrorResponse("InvalidTitle", 422)], - [['category_id' => 47], ['folder' => 46], new ExceptionInput("idMissing"), new ErrorResponse("MissingCategory", 422)], + [[], [], new ExceptionInput("subjectMissing"), V1::respError("404", 404)], + [['title' => ""], ['title' => ""], new ExceptionInput("missing"), V1::respError("InvalidTitle", 422)], + [['title' => " "], ['title' => " "], new ExceptionInput("whitespace"), V1::respError("InvalidTitle", 422)], + [['title' => " "], ['title' => " "], new ExceptionInput("whitespace"), V1::respError("InvalidTitle", 422)], + [['category_id' => 47], ['folder' => 46], new ExceptionInput("idMissing"), V1::respError("MissingCategory", 422)], [['crawler' => false], ['scrape' => false], true, $success], [['keeplist_rules' => ""], ['keep_rule' => ""], true, $success], [['blocklist_rules' => "ook"], ['block_rule' => "ook"], true, $success], @@ -685,7 +684,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function testDeleteAMissingFeed(): void { $this->dbMock->subscriptionRemove->throws(new ExceptionInput("subjectMissing")); - $this->assertMessage(new ErrorResponse("404", 404), $this->req("DELETE", "/feeds/2112")); + $this->assertMessage(V1::respError("404", 404), $this->req("DELETE", "/feeds/2112")); $this->dbMock->subscriptionRemove->calledWith(Arsse::$user->id, 2112); } @@ -703,11 +702,11 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideIcons(): iterable { return [ [['id' => 44, 'type' => "image/svg+xml", 'data' => ""], HTTP::respJson(['id' => 44, 'data' => "image/svg+xml;base64,PHN2Zy8+", 'mime_type' => "image/svg+xml"])], - [['id' => 47, 'type' => "", 'data' => ""], new ErrorResponse("404", 404)], - [['id' => 47, 'type' => null, 'data' => ""], new ErrorResponse("404", 404)], - [['id' => 47, 'type' => null, 'data' => null], new ErrorResponse("404", 404)], - [null, new ErrorResponse("404", 404)], - [new ExceptionInput("subjectMissing"), new ErrorResponse("404", 404)], + [['id' => 47, 'type' => "", 'data' => ""], V1::respError("404", 404)], + [['id' => 47, 'type' => null, 'data' => ""], V1::respError("404", 404)], + [['id' => 47, 'type' => null, 'data' => null], V1::respError("404", 404)], + [null, V1::respError("404", 404)], + [new ExceptionInput("subjectMissing"), V1::respError("404", 404)], ]; } @@ -743,17 +742,17 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { $c = (new Context)->limit(100); $o = ["modified_date"]; // the default sort order return [ - ["/entries?after=A", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "after"], 400)], - ["/entries?before=B", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "before"], 400)], - ["/entries?category_id=0", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "category_id"], 400)], - ["/entries?after_entry_id=0", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "after_entry_id"], 400)], - ["/entries?before_entry_id=0", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "before_entry_id"], 400)], - ["/entries?limit=-1", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "limit"], 400)], - ["/entries?offset=-1", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "offset"], 400)], - ["/entries?direction=sideways", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "direction"], 400)], - ["/entries?order=false", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "order"], 400)], - ["/entries?starred&starred", null, null, [], false, new ErrorResponse(["DuplicateInputValue", 'field' => "starred"], 400)], - ["/entries?after&after=0", null, null, [], false, new ErrorResponse(["DuplicateInputValue", 'field' => "after"], 400)], + ["/entries?after=A", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "after"], 400)], + ["/entries?before=B", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "before"], 400)], + ["/entries?category_id=0", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "category_id"], 400)], + ["/entries?after_entry_id=0", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "after_entry_id"], 400)], + ["/entries?before_entry_id=0", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "before_entry_id"], 400)], + ["/entries?limit=-1", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "limit"], 400)], + ["/entries?offset=-1", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "offset"], 400)], + ["/entries?direction=sideways", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "direction"], 400)], + ["/entries?order=false", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "order"], 400)], + ["/entries?starred&starred", null, null, [], false, V1::respError(["DuplicateInputValue", 'field' => "starred"], 400)], + ["/entries?after&after=0", null, null, [], false, V1::respError(["DuplicateInputValue", 'field' => "after"], 400)], ["/entries", $c, $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], ["/entries?category_id=47", (clone $c)->folder(46), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], ["/entries?category_id=1", (clone $c)->folderShallow(0), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], @@ -790,15 +789,15 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { ["/entries?order=category_id&direction=desc", $c, ["top_folder desc"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], ["/entries?order=category_title&direction=desc", $c, ["top_folder_name desc"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], ["/entries?order=status&direction=desc", $c, ["hidden desc", "unread"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/entries?category_id=2112", (clone $c)->folder(2111), $o, new ExceptionInput("idMissing"), false, new ErrorResponse("MissingCategory")], + ["/entries?category_id=2112", (clone $c)->folder(2111), $o, new ExceptionInput("idMissing"), false, V1::respError("MissingCategory")], ["/feeds/42/entries", (clone $c)->subscription(42), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], ["/feeds/42/entries?category_id=47", (clone $c)->subscription(42)->folder(46), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/feeds/2112/entries", (clone $c)->subscription(2112), $o, new ExceptionInput("idMissing"), false, new ErrorResponse("404", 404)], + ["/feeds/2112/entries", (clone $c)->subscription(2112), $o, new ExceptionInput("idMissing"), false, V1::respError("404", 404)], ["/categories/42/entries", (clone $c)->folder(41), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], ["/categories/42/entries?category_id=47", (clone $c)->folder(41), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], ["/categories/42/entries?starred", (clone $c)->folder(41)->starred(true), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], ["/categories/1/entries", (clone $c)->folderShallow(0), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], - ["/categories/2112/entries", (clone $c)->folder(2111), $o, new ExceptionInput("idMissing"), false, new ErrorResponse("404", 404)], + ["/categories/2112/entries", (clone $c)->folder(2111), $o, new ExceptionInput("idMissing"), false, V1::respError("404", 404)], ]; } @@ -828,15 +827,15 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { $c = new Context; return [ ["/entries/42", (clone $c)->article(42), [self::ENTRIES[1]], HTTP::respJson(self::ENTRIES_OUT[1])], - ["/entries/2112", (clone $c)->article(2112), new ExceptionInput("subjectMissing"), new ErrorResponse("404", 404)], + ["/entries/2112", (clone $c)->article(2112), new ExceptionInput("subjectMissing"), V1::respError("404", 404)], ["/feeds/47/entries/42", (clone $c)->subscription(47)->article(42), [self::ENTRIES[1]], HTTP::respJson(self::ENTRIES_OUT[1])], - ["/feeds/47/entries/44", (clone $c)->subscription(47)->article(44), [], new ErrorResponse("404", 404)], - ["/feeds/47/entries/2112", (clone $c)->subscription(47)->article(2112), new ExceptionInput("subjectMissing"), new ErrorResponse("404", 404)], - ["/feeds/2112/entries/47", (clone $c)->subscription(2112)->article(47), new ExceptionInput("idMissing"), new ErrorResponse("404", 404)], + ["/feeds/47/entries/44", (clone $c)->subscription(47)->article(44), [], V1::respError("404", 404)], + ["/feeds/47/entries/2112", (clone $c)->subscription(47)->article(2112), new ExceptionInput("subjectMissing"), V1::respError("404", 404)], + ["/feeds/2112/entries/47", (clone $c)->subscription(2112)->article(47), new ExceptionInput("idMissing"), V1::respError("404", 404)], ["/categories/47/entries/42", (clone $c)->folder(46)->article(42), [self::ENTRIES[1]], HTTP::respJson(self::ENTRIES_OUT[1])], - ["/categories/47/entries/44", (clone $c)->folder(46)->article(44), [], new ErrorResponse("404", 404)], - ["/categories/47/entries/2112", (clone $c)->folder(46)->article(2112), new ExceptionInput("subjectMissing"), new ErrorResponse("404", 404)], - ["/categories/2112/entries/47", (clone $c)->folder(2111)->article(47), new ExceptionInput("idMissing"), new ErrorResponse("404", 404)], + ["/categories/47/entries/44", (clone $c)->folder(46)->article(44), [], V1::respError("404", 404)], + ["/categories/47/entries/2112", (clone $c)->folder(46)->article(2112), new ExceptionInput("subjectMissing"), V1::respError("404", 404)], + ["/categories/2112/entries/47", (clone $c)->folder(2111)->article(47), new ExceptionInput("idMissing"), V1::respError("404", 404)], ["/categories/1/entries/42", (clone $c)->folderShallow(0)->article(42), [self::ENTRIES[1]], HTTP::respJson(self::ENTRIES_OUT[1])], ]; } @@ -855,14 +854,14 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideEntryMarkings(): iterable { self::clearData(); return [ - [['status' => "read"], null, new ErrorResponse(["MissingInputValue", 'field' => "entry_ids"], 422)], - [['entry_ids' => [1]], null, new ErrorResponse(["MissingInputValue", 'field' => "status"], 422)], - [['entry_ids' => [], 'status' => "read"], null, new ErrorResponse(["MissingInputValue", 'field' => "entry_ids"], 422)], - [['entry_ids' => 1, 'status' => "read"], null, new ErrorResponse(["InvalidInputType", 'field' => "entry_ids", 'expected' => "array", 'actual' => "integer"], 422)], - [['entry_ids' => ["1"], 'status' => "read"], null, new ErrorResponse(["InvalidInputType", 'field' => "entry_ids", 'expected' => "integer", 'actual' => "string"], 422)], - [['entry_ids' => [1], 'status' => 1], null, new ErrorResponse(["InvalidInputType", 'field' => "status", 'expected' => "string", 'actual' => "integer"], 422)], - [['entry_ids' => [0], 'status' => "read"], null, new ErrorResponse(["InvalidInputValue", 'field' => "entry_ids"], 422)], - [['entry_ids' => [1], 'status' => "reread"], null, new ErrorResponse(["InvalidInputValue", 'field' => "status"], 422)], + [['status' => "read"], null, V1::respError(["MissingInputValue", 'field' => "entry_ids"], 422)], + [['entry_ids' => [1]], null, V1::respError(["MissingInputValue", 'field' => "status"], 422)], + [['entry_ids' => [], 'status' => "read"], null, V1::respError(["MissingInputValue", 'field' => "entry_ids"], 422)], + [['entry_ids' => 1, 'status' => "read"], null, V1::respError(["InvalidInputType", 'field' => "entry_ids", 'expected' => "array", 'actual' => "integer"], 422)], + [['entry_ids' => ["1"], 'status' => "read"], null, V1::respError(["InvalidInputType", 'field' => "entry_ids", 'expected' => "integer", 'actual' => "string"], 422)], + [['entry_ids' => [1], 'status' => 1], null, V1::respError(["InvalidInputType", 'field' => "status", 'expected' => "string", 'actual' => "integer"], 422)], + [['entry_ids' => [0], 'status' => "read"], null, V1::respError(["InvalidInputValue", 'field' => "entry_ids"], 422)], + [['entry_ids' => [1], 'status' => "reread"], null, V1::respError(["InvalidInputValue", 'field' => "status"], 422)], [['entry_ids' => [1, 2], 'status' => "read"], ['read' => true, 'hidden' => false], HTTP::respEmpty(204)], [['entry_ids' => [1, 2], 'status' => "unread"], ['read' => false, 'hidden' => false], HTTP::respEmpty(204)], [['entry_ids' => [1, 2], 'status' => "removed"], ['read' => true, 'hidden' => true], HTTP::respEmpty(204)], @@ -889,11 +888,11 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { $c = (new Context)->hidden(false); return [ ["/users/42/mark-all-as-read", $c, 1123, HTTP::respEmpty(204)], - ["/users/2112/mark-all-as-read", $c, null, new ErrorResponse("403", 403)], + ["/users/2112/mark-all-as-read", $c, null, V1::respError("403", 403)], ["/feeds/47/mark-all-as-read", (clone $c)->subscription(47), 2112, HTTP::respEmpty(204)], - ["/feeds/2112/mark-all-as-read", (clone $c)->subscription(2112), new ExceptionInput("idMissing"), new ErrorResponse("404", 404)], + ["/feeds/2112/mark-all-as-read", (clone $c)->subscription(2112), new ExceptionInput("idMissing"), V1::respError("404", 404)], ["/categories/47/mark-all-as-read", (clone $c)->folder(46), 1337, HTTP::respEmpty(204)], - ["/categories/2112/mark-all-as-read", (clone $c)->folder(2111), new ExceptionInput("idMissing"), new ErrorResponse("404", 404)], + ["/categories/2112/mark-all-as-read", (clone $c)->folder(2111), new ExceptionInput("idMissing"), V1::respError("404", 404)], ["/categories/1/mark-all-as-read", (clone $c)->folderShallow(0), 6666, HTTP::respEmpty(204)], ]; } @@ -930,7 +929,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { return [ [1, true, HTTP::respEmpty(204)], [0, false, HTTP::respEmpty(204)], - [new ExceptionInput("subjectMissing"), null, new ErrorResponse("404", 404)], + [new ExceptionInput("subjectMissing"), null, V1::respError("404", 404)], ]; } @@ -942,7 +941,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function testRefreshAMissingFeed(): void { $this->dbMock->subscriptionPropertiesGet->throws(new ExceptionInput("subjectMissing")); - $this->assertMessage(new ErrorResponse("404", 404), $this->req("PUT", "/feeds/2112/refresh")); + $this->assertMessage(V1::respError("404", 404), $this->req("PUT", "/feeds/2112/refresh")); $this->dbMock->subscriptionPropertiesGet->calledWith(Arsse::$user->id, 2112); } @@ -963,12 +962,12 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideImports(): iterable { self::clearData(); return [ - [new ImportException("invalidSyntax"), new ErrorResponse("InvalidBodyXML", 400)], - [new ImportException("invalidSemantics"), new ErrorResponse("InvalidBodyOPML", 422)], - [new ImportException("invalidFolderName"), new ErrorResponse("InvalidImportCategory", 422)], - [new ImportException("invalidFolderCopy"), new ErrorResponse("DuplicateImportCategory", 422)], - [new ImportException("invalidTagName"), new ErrorResponse("InvalidImportLabel", 422)], - [new FeedException("invalidUrl", ['url' => "http://example.com/"]), new ErrorResponse(["FailedImportFeed", 'url' => "http://example.com/", 'code' => 10502], 502)], + [new ImportException("invalidSyntax"), V1::respError("InvalidBodyXML", 400)], + [new ImportException("invalidSemantics"), V1::respError("InvalidBodyOPML", 422)], + [new ImportException("invalidFolderName"), V1::respError("InvalidImportCategory", 422)], + [new ImportException("invalidFolderCopy"), V1::respError("DuplicateImportCategory", 422)], + [new ImportException("invalidTagName"), V1::respError("InvalidImportLabel", 422)], + [new FeedException("invalidUrl", ['url' => "http://example.com/"]), V1::respError(["FailedImportFeed", 'url' => "http://example.com/", 'code' => 10502], 502)], [true, HTTP::respJson(['message' => Arsse::$lang->msg("API.Miniflux.ImportSuccess")])], ]; } @@ -976,8 +975,8 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function testExport(): void { $opml = $this->mock(OPML::class); $this->objMock->get->with(OPML::class)->returns($opml); - $opml->export->returns("EXPORT DATA"); - $this->assertMessage(new TextResponse("EXPORT DATA", 200, ['Content-Type' => "application/xml"]), $this->req("GET", "/export")); + $opml->export->returns(""); + $this->assertMessage(HTTP::respText("", 200, ['Content-Type' => "application/xml"]), $this->req("GET", "/export")); $opml->export->calledWith(Arsse::$user->id); } } diff --git a/tests/cases/REST/TestREST.php b/tests/cases/REST/TestREST.php index 58dfa524..9dd98612 100644 --- a/tests/cases/REST/TestREST.php +++ b/tests/cases/REST/TestREST.php @@ -242,7 +242,7 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { ["OPTIONS", ['Origin' => "http://example", 'Access-Control-Request-Headers' => ["Content-Type", "If-None-Match"]], [], [ 'Access-Control-Allow-Origin' => "http://example", 'Access-Control-Allow-Credentials' => "true", - 'Access-Control-Allow-Headers' => "Content-Type,If-None-Match", + 'Access-Control-Allow-Headers' => "Content-Type, If-None-Match", 'Access-Control-Max-Age' => (string) (60 * 60 * 24), 'Vary' => "Origin", ]], @@ -280,8 +280,8 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { [HTTP::respText("", 200), HTTP::respText("", 200, ['Content-Length' => "0"])], [HTTP::respText("ook", 404), HTTP::respText("ook", 404, ['Content-Length' => "3"])], [HTTP::respText("", 404), HTTP::respText("", 404)], - [new Response(200, [], $stream), new Response(200, ['Content-Length' => "3"], $stream), new Request("", "GET")], - [new Response(200, [], $stream), HTTP::respEmpty(200, ['Content-Length' => "3"]), new Request("", "HEAD")], + [new Response(200, [], $stream), new Response(200, ['Content-Length' => "3"], $stream), new Request("GET", "")], + [new Response(200, [], $stream), HTTP::respEmpty(200, ['Content-Length' => "3"]), new Request("HEAD", "")], ]; } diff --git a/tests/cases/REST/TinyTinyRSS/TestAPI.php b/tests/cases/REST/TinyTinyRSS/TestAPI.php index 96d50c30..c31a6655 100644 --- a/tests/cases/REST/TinyTinyRSS/TestAPI.php +++ b/tests/cases/REST/TinyTinyRSS/TestAPI.php @@ -1685,10 +1685,10 @@ LONG_STRING; $this->assertMessage($this->outputHeadlines(1), $test); // test 'show_content' $test = $this->req($in[1]); - $this->assertArrayHasKey("content", $test->getPayload()['content'][0]); - $this->assertArrayHasKey("content", $test->getPayload()['content'][1]); + $this->assertArrayHasKey("content", $this->extractMessageJson($test)['content'][0]); + $this->assertArrayHasKey("content", $this->extractMessageJson($test)['content'][1]); foreach ($this->generateHeadlines(1) as $key => $row) { - $this->assertSame($row['content'], $test->getPayload()['content'][$key]['content']); + $this->assertSame($row['content'], $this->extractMessageJson($test)['content'][$key]['content']); } // test 'include_attachments' $test = $this->req($in[2]); @@ -1704,22 +1704,22 @@ LONG_STRING; 'post_id' => "2112", ], ]; - $this->assertArrayHasKey("attachments", $test->getPayload()['content'][0]); - $this->assertArrayHasKey("attachments", $test->getPayload()['content'][1]); - $this->assertSame([], $test->getPayload()['content'][0]['attachments']); - $this->assertSame($exp, $test->getPayload()['content'][1]['attachments']); + $this->assertArrayHasKey("attachments", $this->extractMessageJson($test)['content'][0]); + $this->assertArrayHasKey("attachments", $this->extractMessageJson($test)['content'][1]); + $this->assertSame([], $this->extractMessageJson($test)['content'][0]['attachments']); + $this->assertSame($exp, $this->extractMessageJson($test)['content'][1]['attachments']); // test 'include_header' $test = $this->req($in[3]); $exp = $this->respGood([ ['id' => -4, 'is_cat' => false, 'first_id' => 1], - $this->outputHeadlines(1)->getPayload()['content'], + $this->extractMessageJson($this->outputHeadlines(1))['content'], ]); $this->assertMessage($exp, $test); // test 'include_header' with a category $test = $this->req($in[4]); $exp = $this->respGood([ ['id' => -3, 'is_cat' => true, 'first_id' => 1], - $this->outputHeadlines(1)->getPayload()['content'], + $this->extractMessageJson($this->outputHeadlines(1))['content'], ]); $this->assertMessage($exp, $test); // test 'include_header' with an empty result @@ -1741,7 +1741,7 @@ LONG_STRING; $test = $this->req($in[7]); $exp = $this->respGood([ ['id' => -4, 'is_cat' => false, 'first_id' => 0], - $this->outputHeadlines(1)->getPayload()['content'], + $this->extractMessageJson($this->outputHeadlines(1))['content'], ]); $this->assertMessage($exp, $test); // test 'include_header' with skip @@ -1749,24 +1749,24 @@ LONG_STRING; $test = $this->req($in[8]); $exp = $this->respGood([ ['id' => 42, 'is_cat' => false, 'first_id' => 1867], - $this->outputHeadlines(1)->getPayload()['content'], + $this->extractMessageJson($this->outputHeadlines(1))['content'], ]); $this->assertMessage($exp, $test); // test 'include_header' with skip and ascending order $test = $this->req($in[9]); $exp = $this->respGood([ ['id' => 42, 'is_cat' => false, 'first_id' => 0], - $this->outputHeadlines(1)->getPayload()['content'], + $this->extractMessageJson($this->outputHeadlines(1))['content'], ]); $this->assertMessage($exp, $test); // test 'show_excerpt' $exp1 = "“This & that, you know‽”"; $exp2 = "Pour vous faire mieux connaitre d’ou\u{300} vient l’erreur de ceux qui bla\u{302}ment la volupte\u{301}, et qui louent en…"; $test = $this->req($in[10]); - $this->assertArrayHasKey("excerpt", $test->getPayload()['content'][0]); - $this->assertArrayHasKey("excerpt", $test->getPayload()['content'][1]); - $this->assertSame($exp1, $test->getPayload()['content'][0]['excerpt']); - $this->assertSame($exp2, $test->getPayload()['content'][1]['excerpt']); + $this->assertArrayHasKey("excerpt", $this->extractMessageJson($test)['content'][0]); + $this->assertArrayHasKey("excerpt", $this->extractMessageJson($test)['content'][1]); + $this->assertSame($exp1, $this->extractMessageJson($test)['content'][0]['excerpt']); + $this->assertSame($exp2, $this->extractMessageJson($test)['content'][1]['excerpt']); } protected function generateHeadlines(int $id): Result { diff --git a/tests/lib/AbstractTest.php b/tests/lib/AbstractTest.php index c155a192..77653ee8 100644 --- a/tests/lib/AbstractTest.php +++ b/tests/lib/AbstractTest.php @@ -24,8 +24,7 @@ use Psr\Http\Message\MessageInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\ServerRequest; -use Laminas\Diactoros\Response\XmlResponse; +use GuzzleHttp\Psr7\ServerRequest; /** @coversNothing */ abstract class AbstractTest extends \PHPUnit\Framework\TestCase { @@ -112,7 +111,7 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase { } } $server = array_merge($server, $vars); - $req = new ServerRequest($server, [], $url, $method, "php://memory", [], [], $params, $parsedBody); + $req = new ServerRequest($method, $url, $headers, $body, "1.1", $server); if (isset($user)) { if (strlen($user)) { $req = $req->withAttribute("authenticated", true)->withAttribute("authenticatedUser", $user); @@ -192,8 +191,8 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase { $this->assertSame($exp->getRequestTarget(), $act->getRequestTarget(), $text); } if ($exp instanceof ResponseInterface && HTTP::matchType($exp, "application/json", "text/json", "+json")) { - $expBody = json_decode((string) $exp->getBody(), true); - $actBody = json_decode((string) $act->getBody(), true); + $expBody = @json_decode((string) $exp->getBody(), true); + $actBody = @json_decode((string) $act->getBody(), true); $this->assertSame(\JSON_ERROR_NONE, json_last_error(), "Response body is not valid JSON"); $this->assertEquals($expBody, $actBody, $text); $this->assertSame($expBody, $actBody, $text); @@ -205,6 +204,16 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase { $this->assertEquals($exp->getHeaders(), $act->getHeaders(), $text); } + protected function extractMessageJson(MessageInterface $msg) { + if (HTTP::matchType($msg, "application/json", "text/json", "+json")) { + $json = @json_decode((string) $msg->getBody(), true); + if (json_last_error() === \JSON_ERROR_NONE) { + return $json; + } + } + return null; + } + public function assertTime($exp, $test, string $msg = ''): void { $test = $this->approximateTime($exp, $test); $exp = Date::transform($exp, "iso8601"); diff --git a/tests/phpunit.dist.xml b/tests/phpunit.dist.xml index bd01e8f6..f50257c5 100644 --- a/tests/phpunit.dist.xml +++ b/tests/phpunit.dist.xml @@ -115,7 +115,6 @@ cases/REST/TestREST.php - cases/REST/Miniflux/TestErrorResponse.php cases/REST/Miniflux/TestStatus.php cases/REST/Miniflux/TestV1.php cases/REST/Miniflux/TestToken.php From d2f3f191286913c0b6ef0f760b33cc934f99a9a3 Mon Sep 17 00:00:00 2001 From: "J. King" Date: Sat, 6 Aug 2022 16:16:18 -0400 Subject: [PATCH 11/16] Fix failures --- tests/lib/AbstractTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/lib/AbstractTest.php b/tests/lib/AbstractTest.php index 77653ee8..53467aa5 100644 --- a/tests/lib/AbstractTest.php +++ b/tests/lib/AbstractTest.php @@ -112,6 +112,7 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase { } $server = array_merge($server, $vars); $req = new ServerRequest($method, $url, $headers, $body, "1.1", $server); + $req = $req->withParsedBody($parsedBody)->withQueryParams($params); if (isset($user)) { if (strlen($user)) { $req = $req->withAttribute("authenticated", true)->withAttribute("authenticatedUser", $user); From 3be3f43babcc67637f54cf1481b460557fa31144 Mon Sep 17 00:00:00 2001 From: "J. King" Date: Sat, 6 Aug 2022 22:59:25 -0400 Subject: [PATCH 12/16] Start on tests for response wrappers --- tests/cases/Misc/TestHTTP.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/cases/Misc/TestHTTP.php b/tests/cases/Misc/TestHTTP.php index b4a580ed..71eec8c7 100644 --- a/tests/cases/Misc/TestHTTP.php +++ b/tests/cases/Misc/TestHTTP.php @@ -9,6 +9,7 @@ namespace JKingWeb\Arsse\TestCase\Misc; use JKingWeb\Arsse\Misc\HTTP; use GuzzleHttp\Psr7\Request; use GuzzleHttp\Psr7\Response; +use Psr\Http\Message\ResponseInterface; /** @covers \JKingWeb\Arsse\Misc\HTTP */ class TestHTTP extends \JKingWeb\Arsse\Test\AbstractTest { @@ -29,6 +30,22 @@ class TestHTTP extends \JKingWeb\Arsse\Test\AbstractTest { ["", ["application/json"], false], ["", ["application/json", ""], true], ["application/json ;", ["application/json"], true], + ["application/feed+json", ["application/json", "+json"], true], + ["application/xhtml+xml", ["application/json", "+json"], false], + ]; + } + + /** @dataProvider provideTypedMessages */ + public function testCreateResponses(string $type, array $params, ResponseInterface $exp): void { + $act = call_user_func(["JKingWeb\\Arsse\\Misc\\HTTP", $type], ...$params); + $this->assertMessage($exp, $act); + } + + public function provideTypedMessages(): iterable { + return [ + ["respEmpty", [422, ['Content-Length' => "0"]], new Response(422, ['Content-Length' => "0"])], + ["respText", ["OOK"], new Response(200, ['Content-Type' => "text/plain; charset=UTF-8"], "OOK")], + ["respText", ["OOK", 201, ['Content-Type' => "application/octet-stream"]], new Response(201, ['Content-Type' => "application/octet-stream"], "OOK")], ]; } } From 136d3782e3d9da938d19f9980f37a17066746b95 Mon Sep 17 00:00:00 2001 From: "J. King" Date: Sun, 7 Aug 2022 20:16:27 -0400 Subject: [PATCH 13/16] Update changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index f6263f2e..ba526b7e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,7 @@ Bug fixes: - Allow multiple date ranges in search strings in Tiny Tiny RSS - Honour user time zone when interpreting search strings in Tiny Tiny RSS - Perform MySQL table maintenance more reliably +- Address CVE-2022-31090, CVE-2022-31091, CVE-2022-29248, and CVE-2022-31109 Version 0.10.2 (2022-04-04) =========================== From 866800dcc501cc52609c80d53062c474b867aa3b Mon Sep 17 00:00:00 2001 From: "J. King" Date: Tue, 13 Sep 2022 19:52:29 -0400 Subject: [PATCH 14/16] Finish last Guzzle-related tests --- locale/en.php | 2 +- tests/cases/Misc/TestHTTP.php | 10 +++++++--- tests/cases/REST/Miniflux/TestV1.php | 6 ++++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/locale/en.php b/locale/en.php index a439a45b..c9546472 100644 --- a/locale/en.php +++ b/locale/en.php @@ -34,7 +34,7 @@ return [ 'API.Miniflux.Error.InvalidTitle' => 'Invalid feed title', 'API.Miniflux.Error.InvalidImportCategory' => 'Payload contains an invalid category name', 'API.Miniflux.Error.DuplicateImportCategory' => 'Payload contains the same category name twice', - 'API.Miniflux.Error.FailedImportFeed' => 'Unable to import feed at URL "{url}" (code {code}', + 'API.Miniflux.Error.FailedImportFeed' => 'Unable to import feed at URL "{url}" (code {code})', 'API.Miniflux.Error.InvalidImportLabel' => 'Payload contains an invalid label name', 'API.TTRSS.Category.Uncategorized' => 'Uncategorized', diff --git a/tests/cases/Misc/TestHTTP.php b/tests/cases/Misc/TestHTTP.php index 71eec8c7..fee9a67a 100644 --- a/tests/cases/Misc/TestHTTP.php +++ b/tests/cases/Misc/TestHTTP.php @@ -43,9 +43,13 @@ class TestHTTP extends \JKingWeb\Arsse\Test\AbstractTest { public function provideTypedMessages(): iterable { return [ - ["respEmpty", [422, ['Content-Length' => "0"]], new Response(422, ['Content-Length' => "0"])], - ["respText", ["OOK"], new Response(200, ['Content-Type' => "text/plain; charset=UTF-8"], "OOK")], - ["respText", ["OOK", 201, ['Content-Type' => "application/octet-stream"]], new Response(201, ['Content-Type' => "application/octet-stream"], "OOK")], + ["respEmpty", [422, ['Content-Length' => "0"]], new Response(422, ['Content-Length' => "0"])], + ["respText", ["OOK"], new Response(200, ['Content-Type' => "text/plain; charset=UTF-8"], "OOK")], + ["respText", ["OOK", 201, ['Content-Type' => "application/octet-stream"]], new Response(201, ['Content-Type' => "application/octet-stream"], "OOK")], + ["respJson", [['ook' => "eek"]], new Response(200, ['Content-Type' => "application/json"], '{"ook":"eek"}')], + ["respJson", [['ook' => "eek"], 400, ['Content-Type' => "application/feed+json"]], new Response(400, ['Content-Type' => "application/feed+json"], '{"ook":"eek"}')], + ["respXml", [""], new Response(200, ['Content-Type' => "application/xml; charset=UTF-8"], "")], + ["respXml", ["", 451, ['Content-Type' => "text/plain", 'Vary' => "ETag"]], new Response(451, ['Content-Type' => "text/plain", 'Vary' => "ETag"], "")], ]; } } diff --git a/tests/cases/REST/Miniflux/TestV1.php b/tests/cases/REST/Miniflux/TestV1.php index ca4ae1fa..9e3aa3cb 100644 --- a/tests/cases/REST/Miniflux/TestV1.php +++ b/tests/cases/REST/Miniflux/TestV1.php @@ -98,6 +98,12 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { return $value; } + public function testGenerateErrorResponse() { + $act = V1::respError(["DuplicateUser", 'user' => "john.doe"], 409, ['Cache-Control' => "no-store"]); + $exp = HTTP::respJson(['error_message' => 'The user name "john.doe" already exists'], 409, ['Cache-Control' => "no-store"]); + $this->assertMessage($exp, $act); + } + /** @dataProvider provideAuthResponses */ public function testAuthenticateAUser($token, bool $auth, bool $success): void { $exp = $success ? HTTP::respEmpty(404) : V1::respError("401", 401); From 44e2c9c13eef7602c2b5615505742a480c2bfac2 Mon Sep 17 00:00:00 2001 From: "J. King" Date: Tue, 13 Sep 2022 19:56:01 -0400 Subject: [PATCH 15/16] Update documentation --- CHANGELOG | 2 +- UPGRADING | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index ba526b7e..c1d10bf7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,4 @@ -Version 0.1?.? (2022-??-??) +Version 0.10.3 (2022-??-??) =========================== Bug fixes: diff --git a/UPGRADING b/UPGRADING index f6dcfff6..da643168 100644 --- a/UPGRADING +++ b/UPGRADING @@ -9,6 +9,13 @@ usually prudent: - Check for any changes to sample systemd unit or other init files - If installing from source, update dependencies with: `composer install -o --no-dev` + + +Upgrading from 0.10.2 to 0.10.3 +============================= + +- The following Composer dependencies have been removed: + - laminas/laminas-diactoros Upgrading from 0.8.5 to 0.9.0 From a25e777ec6e76d864e1cdd987f39581aa2009412 Mon Sep 17 00:00:00 2001 From: "J. King" Date: Wed, 14 Sep 2022 08:06:22 -0400 Subject: [PATCH 16/16] Version bump --- CHANGELOG | 2 +- lib/Arsse.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c1d10bf7..6995ad0a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,4 @@ -Version 0.10.3 (2022-??-??) +Version 0.10.3 (2022-09-14) =========================== Bug fixes: diff --git a/lib/Arsse.php b/lib/Arsse.php index 604bccd1..9d5a57b7 100644 --- a/lib/Arsse.php +++ b/lib/Arsse.php @@ -7,7 +7,7 @@ declare(strict_types=1); namespace JKingWeb\Arsse; class Arsse { - public const VERSION = "0.10.2"; + public const VERSION = "0.10.3"; public const REQUIRED_EXTENSIONS = [ "intl", // as this extension is required to prepare formatted messages, its absence will throw a distinct English-only exception "dom",