From d514c319c0e5285c5f04bcf15e212cc86d3e9fec Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Fri, 2 Nov 2018 12:58:19 -0400 Subject: [PATCH] Update picture helper, move anilist oauth calls to the settings controller --- app/appConf/routes.php | 4 +- src/Controller/Settings.php | 62 +++++++ src/Controller/User.php | 64 -------- src/Helper/Picture.php | 69 ++++++-- tests/AnimeClientTest.php | 9 ++ tests/Helper/PictureHelperTest.php | 151 ++++++++++++++++++ ...eHelper with data set Full webp URL__1.php | 1 + ...lper with data set Partial webp URL__1.php | 1 + ...with data set bmp with gif fallback__1.php | 1 + ...ictureHelper with data set jpeg2000__1.php | 1 + ...with data set png placeholder image__1.php | 1 + ...ta set simple image with attributes__1.php | 1 + ...png fallback and lots of attributes__1.php | 1 + ...ith data set webp placeholder image__1.php | 1 + 14 files changed, 285 insertions(+), 82 deletions(-) create mode 100644 tests/Helper/PictureHelperTest.php create mode 100644 tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set Full webp URL__1.php create mode 100644 tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set Partial webp URL__1.php create mode 100644 tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set bmp with gif fallback__1.php create mode 100644 tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set jpeg2000__1.php create mode 100644 tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set png placeholder image__1.php create mode 100644 tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set simple image with attributes__1.php create mode 100644 tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set svg with png fallback and lots of attributes__1.php create mode 100644 tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set webp placeholder image__1.php diff --git a/app/appConf/routes.php b/app/appConf/routes.php index 50ff8e5c..feadb761 100644 --- a/app/appConf/routes.php +++ b/app/appConf/routes.php @@ -191,12 +191,12 @@ $routes = [ 'anilist-redirect' => [ 'path' => '/anilist-redirect', 'action' => 'anilistRedirect', - 'controller' => 'user', + 'controller' => 'settings', ], 'anilist-callback' => [ 'path' => '/anilist-oauth', 'action' => 'anilistCallback', - 'controller' => 'user', + 'controller' => 'settings', ], 'image_proxy' => [ 'path' => '/public/images/{type}/{file}', diff --git a/src/Controller/Settings.php b/src/Controller/Settings.php index 62214748..6ae5ad8b 100644 --- a/src/Controller/Settings.php +++ b/src/Controller/Settings.php @@ -84,4 +84,66 @@ final class Settings extends BaseController { $this->redirect($this->url->generate('settings'), 303); } + + /** + * Redirect to Anilist to start Oauth flow + */ + public function anilistRedirect() + { + $redirectUrl = 'https://anilist.co/api/v2/oauth/authorize?' . + http_build_query([ + 'client_id' => $this->config->get(['anilist', 'client_id']), + 'redirect_uri' => $this->urlGenerator->url('/anilist-oauth'), + 'response_type' => 'code', + ]); + + $this->redirect($redirectUrl, 303); + } + + /** + * Oauth callback for Anilist API + */ + public function anilistCallback() + { + $query = $this->request->getQueryParams(); + $authCode = $query['code']; + $uri = $this->urlGenerator->url('/anilist-oauth'); + + $authData = $this->anilistModel->authenticate($authCode, $uri); + $settings = $this->settingsModel->getSettings(); + + if (array_key_exists('error', $authData)) + { + $this->errorPage(400, 'Error Linking Account', $authData['hint']); + return; + } + + // Update the override config file + $anilistSettings = [ + 'access_token' => $authData['access_token'], + 'access_token_expires' => (time() - 10) + $authData['expires_in'], + 'refresh_token' => $authData['refresh_token'], + ]; + + $newSettings = $settings; + $newSettings['anilist'] = array_merge($settings['anilist'], $anilistSettings); + + foreach ($newSettings['config'] as $key => $value) + { + $newSettings[$key] = $value; + } + unset($newSettings['config']); + + $saved = $this->settingsModel->saveSettingsFile($newSettings); + + if ($saved) + { + $this->setFlashMessage('Linked Anilist Account', 'success'); + } else + { + $this->setFlashMessage('Error Linking Anilist Account', 'error'); + } + + $this->redirect($this->url->generate('settings'), 303); + } } \ No newline at end of file diff --git a/src/Controller/User.php b/src/Controller/User.php index 59b09a41..3cf8f855 100644 --- a/src/Controller/User.php +++ b/src/Controller/User.php @@ -90,70 +90,6 @@ final class User extends BaseController { 'timeOnAnime' => $timeOnAnime, ]); } - - - /** - * Redirect to Anilist to start Oauth flow - */ - public function anilistRedirect() - { - $redirectUrl = 'https://anilist.co/api/v2/oauth/authorize?' . - http_build_query([ - 'client_id' => $this->config->get(['anilist', 'client_id']), - 'redirect_uri' => $this->urlGenerator->url('/anilist-oauth'), - 'response_type' => 'code', - ]); - - $this->redirect($redirectUrl, 303); - } - - /** - * Oauth callback for Anilist API - */ - public function anilistCallback() - { - $query = $this->request->getQueryParams(); - $authCode = $query['code']; - $uri = $this->urlGenerator->url('/anilist-oauth'); - - $authData = $this->anilistModel->authenticate($authCode, $uri); - $settings = $this->settingsModel->getSettings(); - - if (array_key_exists('error', $authData)) - { - $this->errorPage(400, 'Error Linking Account', $authData['hint']); - return; - } - - // Update the override config file - $anilistSettings = [ - 'access_token' => $authData['access_token'], - 'access_token_expires' => (time() - 10) + $authData['expires_in'], - 'refresh_token' => $authData['refresh_token'], - ]; - - $newSettings = $settings; - $newSettings['anilist'] = array_merge($settings['anilist'], $anilistSettings); - - foreach($newSettings['config'] as $key => $value) - { - $newSettings[$key] = $value; - } - unset($newSettings['config']); - - $saved = $this->settingsModel->saveSettingsFile($newSettings); - - if ($saved) - { - $this->setFlashMessage('Linked Anilist Account', 'success'); - } - else - { - $this->setFlashMessage('Error Linking Anilist Account', 'error'); - } - - $this->redirect($this->url->generate('settings'), 303); - } /** * Reorganize favorites data to be more useful diff --git a/src/Helper/Picture.php b/src/Helper/Picture.php index d37335fd..9e8b2dcc 100644 --- a/src/Helper/Picture.php +++ b/src/Helper/Picture.php @@ -25,49 +25,86 @@ final class Picture { use ContainerAware; + private const MIME_MAP = [ + 'apng' => 'image/vnd.mozilla.apng', + 'bmp' => 'image/bmp', + 'gif' => 'image/gif', + 'ico' => 'image/x-icon', + 'jpeg' => 'image/jpeg', + 'jpf' => 'image/jpx', + 'jpg' => 'image/jpeg', + 'jpx' => 'image/jpx', + 'png' => 'image/png', + 'svg' => 'image/svg+xml', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'webp' => 'image/webp', + ]; + + private const SIMPLE_IMAGE_TYPES = [ + 'gif', + 'jpeg', + 'jpg', + 'png', + ]; + /** - * Create the html f + * Create the html for an html picture element * - * @param string $webp + * @param string $uri * @param string $fallbackExt * @param array $picAttrs * @param array $imgAttrs * @return string */ - public function __invoke(string $webp, string $fallbackExt = 'jpg', $picAttrs = [], $imgAttrs = []): string + public function __invoke(string $uri, string $fallbackExt = 'jpg', array $picAttrs = [], array $imgAttrs = []): string { $urlGenerator = $this->container->get('url-generator'); $helper = $this->container->get('html-helper'); - + // If it is a placeholder image, make the // fallback a png, not a jpg - if (strpos($webp, 'placeholder') !== FALSE) + if (strpos($uri, 'placeholder') !== FALSE) { $fallbackExt = 'png'; } - if (strpos($webp, '//') === FALSE) + if (strpos($uri, '//') === FALSE) { - $webp = $urlGenerator->assetUrl($webp); + $uri = $urlGenerator->assetUrl($uri); } - - $urlParts = explode('.', $webp); + $urlParts = explode('.', $uri); $ext = array_pop($urlParts); $path = implode('.', $urlParts); - $mime = $ext === 'jpg' - ? 'image/jpeg' - : "image/{$ext}"; - $fallbackMime = $fallbackExt === 'jpg' - ? 'image/jpeg' - : "image/{$fallbackExt}"; + $mime = array_key_exists($ext, static::MIME_MAP) + ? static::MIME_MAP[$ext] + : 'image/jpeg'; + + $fallbackMime = array_key_exists($fallbackExt, static::MIME_MAP) + ? static::MIME_MAP[$fallbackExt] + : 'image/jpeg'; + + // For image types that are well-established, just return a + // simple element instead + if ( + $ext === $fallbackExt || + \in_array($ext, static::SIMPLE_IMAGE_TYPES, TRUE) + ) + { + $attrs = ( ! empty($imgAttrs)) + ? $imgAttrs + : $picAttrs; + + return $helper->img($uri, $attrs); + } $fallbackImg = "{$path}.{$fallbackExt}"; $pictureChildren = [ $helper->void('source', [ - 'srcset' => $webp, + 'srcset' => $uri, 'type' => $mime, ]), $helper->void('source', [ diff --git a/tests/AnimeClientTest.php b/tests/AnimeClientTest.php index 7b3c8e07..57948d1e 100644 --- a/tests/AnimeClientTest.php +++ b/tests/AnimeClientTest.php @@ -17,6 +17,7 @@ namespace Aviat\AnimeClient\Tests; use function Aviat\AnimeClient\arrayToToml; +use function Aviat\AnimeClient\isSequentialArray; use function Aviat\AnimeClient\tomlToArray; class AnimeClientTest extends AnimeClientTestCase @@ -55,4 +56,12 @@ class AnimeClientTest extends AnimeClientTestCase $this->assertEquals($arr, $parsedArray); } + + public function testIsSequentialArray() + { + $this->assertFalse(isSequentialArray(0)); + $this->assertFalse(isSequentialArray([50 => 'foo'])); + $this->assertTrue(isSequentialArray([])); + $this->assertTrue(isSequentialArray([1,2,3,4,5])); + } } \ No newline at end of file diff --git a/tests/Helper/PictureHelperTest.php b/tests/Helper/PictureHelperTest.php new file mode 100644 index 00000000..22869673 --- /dev/null +++ b/tests/Helper/PictureHelperTest.php @@ -0,0 +1,151 @@ + + * @copyright 2015 - 2018 Timothy J. Warren + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 4.1 + * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient + */ + +namespace Aviat\AnimeClient\Tests\Helper; + +use Aviat\AnimeClient\Helper\Picture as PictureHelper; +use Aviat\AnimeClient\Tests\AnimeClientTestCase; + +class PictureHelperTest extends AnimeClientTestCase { + /** + * @dataProvider dataPictureCase + */ + public function testPictureHelper($params, $expected = NULL) + { + $helper = new PictureHelper(); + $helper->setContainer($this->container); + + $actual = $helper(...$params); + + if ($expected === NULL) + { + $this->assertMatchesSnapshot($actual); + } + else + { + $this->assertEquals($expected, $actual); + } + } + + /** + * @dataProvider dataSimpleImageCase + */ + public function testSimpleImage(string $ext, bool $isSimple) + { + $helper = new PictureHelper(); + $helper->setContainer($this->container); + + $url = "https://example.com/image.{$ext}"; + $actual = $helper($url); + + $actuallySimple = strpos($actual, 'assertEquals($isSimple, $actuallySimple); + } + + public function testSimpleImageByFallback() + { + $helper = new PictureHelper(); + $helper->setContainer($this->container); + + $actual = $helper("foo.svg", 'svg'); + + $this->assertTrue(strpos($actual, ' [ + 'params' => [ + 'https://www.example.com/image.webp', + ], + ], + 'Partial webp URL' => [ + 'params' => [ + 'images/anime/15424.webp' + ], + ], + 'bmp with gif fallback' => [ + 'params' => [ + 'images/avatar/25.bmp', + 'gif', + ], + ], + 'webp placeholder image' => [ + 'params' => [ + 'images/placeholder.webp', + ] + ], + 'png placeholder image' => [ + 'params' => [ + 'images/placeholder.png', + ] + ], + 'jpeg2000' => [ + 'params' => [ + 'images/foo.jpf', + ] + ], + 'svg with png fallback and lots of attributes' => [ + 'params' => [ + 'images/example.svg', + 'png', + [ 'width' => 200, 'height' => 300 ], + [ 'alt' => 'Example text' ] + ] + ], + 'simple image with attributes' => [ + 'params' => [ + 'images/foo.jpg', + 'jpg', + [ 'x' => 1, 'y' => 1 ], + ['width' => 200, 'height' => 200, 'alt' => 'should exist'], + ] + ] + ]; + } + + public function dataSimpleImageCase() + { + return [ + 'apng' => [ + 'ext' => 'apng', + 'isSimple' => FALSE, + ], + 'gif' => [ + 'ext' => 'gif', + 'isSimple' => TRUE, + ], + 'jpg' => [ + 'ext' => 'jpg', + 'isSimple' => TRUE, + ], + 'jpeg' => [ + 'ext' => 'jpeg', + 'isSimple' => TRUE, + ], + 'png' => [ + 'ext' => 'png', + 'isSimple' => TRUE, + ], + 'webp' => [ + 'ext' => 'webp', + 'isSimple' => FALSE, + ], + ]; + } +} \ No newline at end of file diff --git a/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set Full webp URL__1.php b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set Full webp URL__1.php new file mode 100644 index 00000000..f852d0bc --- /dev/null +++ b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set Full webp URL__1.php @@ -0,0 +1 @@ +'; diff --git a/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set Partial webp URL__1.php b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set Partial webp URL__1.php new file mode 100644 index 00000000..4b6711e0 --- /dev/null +++ b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set Partial webp URL__1.php @@ -0,0 +1 @@ +'; diff --git a/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set bmp with gif fallback__1.php b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set bmp with gif fallback__1.php new file mode 100644 index 00000000..ee4c502d --- /dev/null +++ b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set bmp with gif fallback__1.php @@ -0,0 +1 @@ +'; diff --git a/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set jpeg2000__1.php b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set jpeg2000__1.php new file mode 100644 index 00000000..0cecd592 --- /dev/null +++ b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set jpeg2000__1.php @@ -0,0 +1 @@ +'; diff --git a/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set png placeholder image__1.php b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set png placeholder image__1.php new file mode 100644 index 00000000..054958a1 --- /dev/null +++ b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set png placeholder image__1.php @@ -0,0 +1 @@ +'; diff --git a/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set simple image with attributes__1.php b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set simple image with attributes__1.php new file mode 100644 index 00000000..2b3023ef --- /dev/null +++ b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set simple image with attributes__1.php @@ -0,0 +1 @@ +'; diff --git a/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set svg with png fallback and lots of attributes__1.php b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set svg with png fallback and lots of attributes__1.php new file mode 100644 index 00000000..a8900e93 --- /dev/null +++ b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set svg with png fallback and lots of attributes__1.php @@ -0,0 +1 @@ +Example text'; diff --git a/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set webp placeholder image__1.php b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set webp placeholder image__1.php new file mode 100644 index 00000000..d796ce75 --- /dev/null +++ b/tests/Helper/__snapshots__/PictureHelperTest__testPictureHelper with data set webp placeholder image__1.php @@ -0,0 +1 @@ +';