From 496eb6807893cb308e6a306e006f6b7daa1705fb Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Thu, 12 Jan 2017 15:41:20 -0500 Subject: [PATCH] Really ugly progress commit --- app/bootstrap.php | 1 - app/config/config.toml.example | 6 + app/views/anime/cover.php | 4 +- app/views/anime/details.php | 5 +- app/views/anime/edit.php | 1 + build/phpunit.xml | 1 - composer.json | 8 +- phpunit.xml | 41 +- src/API/JsonAPI.php | 114 +++++- src/API/Kitsu/Auth.php | 12 +- src/API/Kitsu/KitsuModel.php | 22 +- .../Transformer/AnimeListTransformer.php | 41 +- .../Kitsu/Transformer/AnimeTransformer.php | 6 +- src/API/MAL.php | 2 +- src/API/MAL/ListItem.php | 52 +++ src/API/MAL/MALTrait.php | 190 +++++++++ src/API/MAL/Model.php | 88 ++-- .../MAL/Transformer/AnimeListTransformer.php | 46 +++ .../MAL/Transformer/MALToKitsuTransformer.php | 33 ++ src/Controller.php | 3 +- src/Util.php | 1 - tests/API/JsonAPITest.php | 48 +++ .../Transformer/AnimeListTransformerTest.php | 90 ++++ .../Transformer/AnimeTransformerTest.php | 30 ++ tests/API/XMLTest.php | 18 +- tests/AnimeClient_TestCase.php | 9 +- tests/ControllerTest.php | 10 +- tests/test_data/JsonAPI/inlineIncluded.json | 1 + .../{ => JsonAPI}/jsonApiExample.json | 0 .../test_data/JsonAPI/organizedIncludes.json | 385 ++++++++++++++++++ .../Kitsu/animeListItemAfterTransform.json | 28 ++ .../Kitsu/animeListItemBeforeTransform.json | 155 +++++++ tests/test_data/{ => XML}/MALExport.xml | 0 .../{ => XML}/minifiedXmlTestFile.xml | 0 tests/test_data/{ => XML}/xmlTestFile.xml | 0 35 files changed, 1305 insertions(+), 146 deletions(-) create mode 100644 src/API/MAL/ListItem.php create mode 100644 src/API/MAL/MALTrait.php create mode 100644 src/API/MAL/Transformer/AnimeListTransformer.php create mode 100644 src/API/MAL/Transformer/MALToKitsuTransformer.php create mode 100644 tests/API/JsonAPITest.php create mode 100644 tests/API/Kitsu/Transformer/AnimeListTransformerTest.php create mode 100644 tests/API/Kitsu/Transformer/AnimeTransformerTest.php create mode 100644 tests/test_data/JsonAPI/inlineIncluded.json rename tests/test_data/{ => JsonAPI}/jsonApiExample.json (100%) create mode 100644 tests/test_data/JsonAPI/organizedIncludes.json create mode 100644 tests/test_data/Kitsu/animeListItemAfterTransform.json create mode 100644 tests/test_data/Kitsu/animeListItemBeforeTransform.json rename tests/test_data/{ => XML}/MALExport.xml (100%) rename tests/test_data/{ => XML}/minifiedXmlTestFile.xml (100%) rename tests/test_data/{ => XML}/xmlTestFile.xml (100%) diff --git a/app/bootstrap.php b/app/bootstrap.php index 8790c541..8f6dd9f4 100644 --- a/app/bootstrap.php +++ b/app/bootstrap.php @@ -14,7 +14,6 @@ * @link https://github.com/timw4mail/HummingBirdAnimeClient */ - namespace Aviat\AnimeClient; use Aura\Html\HelperLocatorFactory; diff --git a/app/config/config.toml.example b/app/config/config.toml.example index 15637e7a..4fe4b5d5 100644 --- a/app/config/config.toml.example +++ b/app/config/config.toml.example @@ -14,5 +14,11 @@ show_anime_collection = true # do you wish to show the manga collection? show_manga_collection = false +# do you have a My Anime List account set up in mal.toml? +use_mal_api = false + +# cache driver for api calls (NullDriver, SQLDriver, RedisDriver) +cache_driver = "NullDriver" + # path to public directory on the server asset_dir = "/../../public" \ No newline at end of file diff --git a/app/views/anime/cover.php b/app/views/anime/cover.php index c30ea8c3..1f34380b 100644 --- a/app/views/anime/cover.php +++ b/app/views/anime/cover.php @@ -11,11 +11,11 @@
is_authenticated()) continue; ?> -
\ No newline at end of file diff --git a/app/views/anime/edit.php b/app/views/anime/edit.php index e96c6d25..28a0673e 100644 --- a/app/views/anime/edit.php +++ b/app/views/anime/edit.php @@ -77,6 +77,7 @@   + diff --git a/build/phpunit.xml b/build/phpunit.xml index c4e9b784..537121c8 100644 --- a/build/phpunit.xml +++ b/build/phpunit.xml @@ -4,7 +4,6 @@ stopOnFailure="false" bootstrap="../tests/bootstrap.php" beStrictAboutTestsThatDoNotTestAnything="true" - checkForUnintentionallyCoveredCode="true" > diff --git a/composer.json b/composer.json index 5381e2d1..789f6eb1 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,6 @@ } }, "require": { - "abeautifulsite/simpleimage": "2.5.*", "aura/html": "2.*", "aura/router": "3.*", "aura/session": "2.*", @@ -35,15 +34,16 @@ "theseer/phpdox": "0.8.1.1", "phploc/phploc": "^3.0", "phpmd/phpmd": "^2.4", - "phpunit/phpunit": "^5.4", + "phpunit/phpunit": "^5.7", "robmorgan/phinx": "^0.6.4", "humbug/humbug": "~1.0@dev", - "consolidation/robo": "~1.0@RC", + "consolidation/robo": "~1.0", "henrikbjorn/lurker": "^1.1.0", "symfony/var-dumper": "^3.1", "squizlabs/php_codesniffer": "^3.0.0@beta" }, "scripts": { - "build:css": "cd public && npm run build && cd .." + "build:css": "cd public && npm run build && cd ..", + "watch:css": "cd public && npm run watch" } } \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml index 73a77ae7..476b10c8 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,25 +1,24 @@ - - - src - - - - - tests - - - - - - - - - + + + src + + + + + tests + + + + + + + + + \ No newline at end of file diff --git a/src/API/JsonAPI.php b/src/API/JsonAPI.php index f2848474..1ea85ca2 100644 --- a/src/API/JsonAPI.php +++ b/src/API/JsonAPI.php @@ -16,6 +16,8 @@ namespace Aviat\AnimeClient\API; +use Aviat\Ion\Json; + /** * Class encapsulating Json API data structure for a request or response */ @@ -52,7 +54,7 @@ class JsonAPI { * * @var array */ - protected $included = []; + public $included = []; /** * Pagination links @@ -70,6 +72,11 @@ class JsonAPI { { $this->data = $initial; } + + public function parseFromString(string $json) + { + $this->parse(Json::decode($json)); + } /** * Parse a JsonAPI response into its components @@ -78,7 +85,7 @@ class JsonAPI { */ public function parse(array $data) { - + $this->included = static::organizeIncludes($data['included']); } /** @@ -91,4 +98,107 @@ class JsonAPI { { } + + /** + * Take inlined included data and inline it into the main object's relationships + * + * @param array $mainObject + * @param array $included + * @return array + */ + public static function inlineIncludedIntoMainObject(array $mainObject, array $included): array + { + $output = clone $mainObject; + } + + /** + * Take organized includes and inline them, where applicable + * + * @param array $included + * @param string $key The key of the include to inline the other included values into + * @return array + */ + public static function inlineIncludedRelationships(array $included, string $key): array + { + $inlined = [ + $key => [] + ]; + + foreach ($included[$key] as $itemId => $item) + { + // Duplicate the item for the output + $inlined[$key][$itemId] = $item; + + foreach($item['relationships'] as $type => $ids) + { + $inlined[$key][$itemId]['relationships'][$type] = []; + foreach($ids as $id) + { + $inlined[$key][$itemId]['relationships'][$type][$id] = $included[$type][$id]; + } + } + } + + return $inlined; + } + + /** + * Reorganizes 'included' data to be keyed by + * type => [ + * id => data/attributes, + * ] + * + * @param array $includes + * @return array + */ + public static function organizeIncludes(array $includes): array + { + $organized = []; + + foreach ($includes as $item) + { + $type = $item['type']; + $id = $item['id']; + $organized[$type] = $organized[$type] ?? []; + $organized[$type][$id] = $item['attributes']; + + if (array_key_exists('relationships', $item)) + { + $organized[$type][$id]['relationships'] = static::organizeRelationships($item['relationships']); + } + } + + return $organized; + } + + /** + * Reorganize relationship mappings to make them simpler to use + * + * Remove verbose structure, and just map: + * type => [ idArray ] + * + * @param array $relationships + * @return array + */ + public static function organizeRelationships(array $relationships): array + { + $organized = []; + + foreach($relationships as $key => $data) + { + if ( ! array_key_exists('data', $data)) + { + continue; + } + + $organized[$key] = $organized[$key] ?? []; + + foreach ($data['data'] as $item) + { + $organized[$key][] = $item['id']; + } + } + + return $organized; + } } \ No newline at end of file diff --git a/src/API/Kitsu/Auth.php b/src/API/Kitsu/Auth.php index c6ac74ab..04e2e395 100644 --- a/src/API/Kitsu/Auth.php +++ b/src/API/Kitsu/Auth.php @@ -18,6 +18,7 @@ namespace Aviat\AnimeClient\API\Kitsu; use Aviat\AnimeClient\AnimeClient; use Aviat\Ion\Di\{ContainerAware, ContainerInterface}; +use Exception; /** * Kitsu API Authentication @@ -64,7 +65,16 @@ class Auth { { $config = $this->container->get('config'); $username = $config->get(['kitsu_username']); - $auth_token = $this->model->authenticate($username, $password); + + try + { + $auth_token = $this->model->authenticate($username, $password); + } + catch (Exception $e) + { + return FALSE; + } + if (FALSE !== $auth_token) { diff --git a/src/API/Kitsu/KitsuModel.php b/src/API/Kitsu/KitsuModel.php index 967392ee..e1adfa08 100644 --- a/src/API/Kitsu/KitsuModel.php +++ b/src/API/Kitsu/KitsuModel.php @@ -16,6 +16,7 @@ namespace Aviat\AnimeClient\API\Kitsu; +use Aviat\AnimeClient\API\JsonAPI; use Aviat\AnimeClient\API\Kitsu as K; use Aviat\AnimeClient\API\Kitsu\Transformer\{ AnimeTransformer, AnimeListTransformer, MangaTransformer, MangaListTransformer @@ -155,30 +156,23 @@ class KitsuModel { 'media_type' => 'Anime', 'status' => $status, ], - 'include' => 'media,media.genres', + 'include' => 'media,media.genres,media.mappings', 'page' => [ 'offset' => 0, - 'limit' => 1000 + 'limit' => 500 ], 'sort' => '-updated_at' ] ]; $data = $this->getRequest('library-entries', $options); - $included = K::organizeIncludes($data['included']); + $included = JsonAPI::organizeIncludes($data['included']); + $included = JsonAPI::inlineIncludedRelationships($included, 'anime'); foreach($data['data'] as $i => &$item) { - $item['anime'] = $included['anime'][$item['relationships']['media']['data']['id']]; - - $animeGenres = $item['anime']['relationships']['genres']; - - foreach($animeGenres as $id) - { - $item['genres'][] = $included['genres'][$id]['name']; - } + $item['included'] =& $included; } - $transformed = $this->animeListTransformer->transformCollection($data['data']); return $transformed; @@ -309,11 +303,7 @@ class KitsuModel { ]; $data = $this->getRequest($type, $options); - $baseData = $data['data'][0]['attributes']; - $rawGenres = array_pluck($data['included'], 'attributes'); - $genres = array_pluck($rawGenres, 'name'); - $baseData['genres'] = $genres; $baseData['included'] = $data['included']; return $baseData; } diff --git a/src/API/Kitsu/Transformer/AnimeListTransformer.php b/src/API/Kitsu/Transformer/AnimeListTransformer.php index 7d05e76e..6f1817cf 100644 --- a/src/API/Kitsu/Transformer/AnimeListTransformer.php +++ b/src/API/Kitsu/Transformer/AnimeListTransformer.php @@ -33,19 +33,35 @@ class AnimeListTransformer extends AbstractTransformer { */ public function transform($item) { -/* ?>
$item['id'], + 'mal_id' => $MALid, 'episodes' => [ 'watched' => $item['attributes']['progress'], 'total' => $total_episodes, @@ -60,7 +76,6 @@ class AnimeListTransformer extends AbstractTransformer { 'age_rating' => $anime['ageRating'], 'titles' => Kitsu::filterTitles($anime), 'slug' => $anime['slug'], - 'url' => $anime['url'] ?? '', 'type' => $this->string($anime['showType'])->upperCaseFirst()->__toString(), 'image' => $anime['posterImage']['small'], 'genres' => $genres, @@ -69,7 +84,7 @@ class AnimeListTransformer extends AbstractTransformer { 'notes' => $item['attributes']['notes'], 'rewatching' => (bool) $item['attributes']['reconsuming'], 'rewatched' => (int) $item['attributes']['reconsumeCount'], - 'user_rating' => ($rating === 0) ? '-' : $rating, + 'user_rating' => ($rating === 0) ? '-' : (int) $rating, 'private' => (bool) $item['attributes']['private'] ?? false, ]; } @@ -83,18 +98,8 @@ class AnimeListTransformer extends AbstractTransformer { */ public function untransform($item) { - // Messy mapping of boolean values to their API string equivalents - $privacy = 'false'; - if (array_key_exists('private', $item) && $item['private']) - { - $privacy = 'true'; - } - - $rewatching = 'false'; - if (array_key_exists('rewatching', $item) && $item['rewatching']) - { - $rewatching = 'true'; - } + $privacy = (array_key_exists('private', $item) && $item['private']); + $rewatching = (array_key_exists('rewatching', $item) && $item['rewatching']); $untransformed = [ 'id' => $item['id'], diff --git a/src/API/Kitsu/Transformer/AnimeTransformer.php b/src/API/Kitsu/Transformer/AnimeTransformer.php index 92c7ee7b..e4339886 100644 --- a/src/API/Kitsu/Transformer/AnimeTransformer.php +++ b/src/API/Kitsu/Transformer/AnimeTransformer.php @@ -16,7 +16,7 @@ namespace Aviat\AnimeClient\API\Kitsu\Transformer; -use Aviat\AnimeClient\API\Kitsu; +use Aviat\AnimeClient\API\{JsonAPI, Kitsu}; use Aviat\Ion\Transformer\AbstractTransformer; /** @@ -33,7 +33,8 @@ class AnimeTransformer extends AbstractTransformer { */ public function transform($item) { - $item['genres'] = $item['genres'] ?? []; + $item['included'] = JsonAPI::organizeIncludes($item['included']); + $item['genres'] = array_column($item['included']['genres'], 'name') ?? []; sort($item['genres']); return [ @@ -48,6 +49,7 @@ class AnimeTransformer extends AbstractTransformer { 'age_rating_guide' => $item['ageRatingGuide'], 'url' => "https://kitsu.io/anime/{$item['slug']}", 'genres' => $item['genres'], + 'included' => $item['included'] ]; } } \ No newline at end of file diff --git a/src/API/MAL.php b/src/API/MAL.php index d6eb2199..ec55f880 100644 --- a/src/API/MAL.php +++ b/src/API/MAL.php @@ -16,7 +16,7 @@ namespace Aviat\AnimeClient\API; -use Aviat\AnimeClient\Enum\{AnimeWatchingStatus, MangaReadingStatus}; +use Aviat\AnimeClient\API\MAL\Enum\{AnimeWatchingStatus, MangaReadingStatus}; /** * Constants and mappings for the My Anime List API diff --git a/src/API/MAL/ListItem.php b/src/API/MAL/ListItem.php new file mode 100644 index 00000000..d5506f9a --- /dev/null +++ b/src/API/MAL/ListItem.php @@ -0,0 +1,52 @@ + + * @copyright 2015 - 2017 Timothy J. Warren + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 4.0 + * @link https://github.com/timw4mail/HummingBirdAnimeClient + */ + +namespace Aviat\AnimeClient\API\MAL; + +use Aviat\AnimeClient\API\AbstractListItem; +use Aviat\Ion\Di\ContainerAware; + +/** + * CRUD operations for MAL list items + */ +class ListItem extends AbstractListItem { + use ContainerAware; + + public function __construct() + { + $this->init(); + } + + public function create(array $data): bool + { + return FALSE; + } + + public function delete(string $id): bool + { + return FALSE; + } + + public function get(string $id): array + { + return []; + } + + public function update(string $id, array $data): Response + { + // @TODO implement + } +} \ No newline at end of file diff --git a/src/API/MAL/MALTrait.php b/src/API/MAL/MALTrait.php new file mode 100644 index 00000000..4d50931e --- /dev/null +++ b/src/API/MAL/MALTrait.php @@ -0,0 +1,190 @@ + + * @copyright 2015 - 2017 Timothy J. Warren + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 4.0 + * @link https://github.com/timw4mail/HummingBirdAnimeClient + */ + +namespace Aviat\AnimeClient\API\MAL; + +use Aviat\AnimeClient\API\{ + GuzzleTrait, + MAL as M, + XML +}; +use GuzzleHttp\Client; +use GuzzleHttp\Cookie\CookieJar; +use GuzzleHttp\Psr7\Response; +use InvalidArgumentException; + +trait MALTrait { + use GuzzleTrait; + + /** + * The base url for api requests + * @var string $base_url + */ + protected $baseUrl = M::BASE_URL; + + /** + * HTTP headers to send with every request + * + * @var array + */ + protected $defaultHeaders = [ + 'User-Agent' => "Tim's Anime Client/4.0" + ]; + + /** + * Set up the class properties + * + * @return void + */ + protected function init() + { + $defaults = [ + 'cookies' => $this->cookieJar, + 'headers' => $this->defaultHeaders, + 'timeout' => 25, + 'connect_timeout' => 25 + ]; + + $this->cookieJar = new CookieJar(); + $this->client = new Client([ + 'base_uri' => $this->baseUrl, + 'cookies' => TRUE, + 'http_errors' => TRUE, + 'defaults' => $defaults + ]); + } + + /** + * Make a request via Guzzle + * + * @param string $type + * @param string $url + * @param array $options + * @return Response + */ + private function getResponse(string $type, string $url, array $options = []) + { + $type = strtoupper($type); + $validTypes = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']; + + if ( ! in_array($type, $validTypes)) + { + throw new InvalidArgumentException('Invalid http request type'); + } + + $config = $this->container->get('config'); + $logger = $this->container->getLogger('request'); + + $defaultOptions = [ + 'auth' => [ + $config->get(['mal','username']), + $config->get(['mal','password']) + ], + 'headers' => $this->defaultHeaders + ]; + + $options = array_merge($defaultOptions, $options); + + $logger->debug(Json::encode([$type, $url])); + $logger->debug(Json::encode($options)); + + return $this->client->request($type, $url, $options); + } + + /** + * Make a request via Guzzle + * + * @param string $type + * @param string $url + * @param array $options + * @return array + */ + private function request(string $type, string $url, array $options = []): array + { + $logger = null; + if ($this->getContainer()) + { + $logger = $this->container->getLogger('request'); + } + + $response = $this->getResponse($type, $url, $options); + + if ((int) $response->getStatusCode() > 299 || (int) $response->getStatusCode() < 200) + { + if ($logger) + { + $logger->warning('Non 200 response for api call'); + $logger->warning($response->getBody()); + } + + // throw new RuntimeException($response->getBody()); + } + + return XML::toArray((string) $response->getBody()); + } + + /** + * Remove some boilerplate for get requests + * + * @param array $args + * @return array + */ + protected function getRequest(...$args): array + { + return $this->request('GET', ...$args); + } + + /** + * Remove some boilerplate for post requests + * + * @param array $args + * @return array + */ + protected function postRequest(...$args): array + { + $logger = null; + if ($this->getContainer()) + { + $logger = $this->container->getLogger('request'); + } + + $response = $this->getResponse('POST', ...$args); + $validResponseCodes = [200, 201]; + + if ( ! in_array((int) $response->getStatusCode(), $validResponseCodes)) + { + if ($logger) + { + $logger->warning('Non 201 response for POST api call'); + $logger->warning($response->getBody()); + } + } + + return XML::toArray((string) $response->getBody()); + } + + /** + * Remove some boilerplate for delete requests + * + * @param array $args + * @return bool + */ + protected function deleteRequest(...$args): bool + { + $response = $this->getResponse('DELETE', ...$args); + return ((int) $response->getStatusCode() === 204); + } +} \ No newline at end of file diff --git a/src/API/MAL/Model.php b/src/API/MAL/Model.php index 47f948f4..b7f0f0c9 100644 --- a/src/API/MAL/Model.php +++ b/src/API/MAL/Model.php @@ -1,63 +1,49 @@ - - * @copyright 2015 - 2017 Timothy J. Warren - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version 4.0 - * @link https://github.com/timw4mail/HummingBirdAnimeClient - */ - -namespace Aviat\AnimeClient\API\Kitsu; + + * @copyright 2015 - 2017 Timothy J. Warren + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 4.0 + * @link https://github.com/timw4mail/HummingBirdAnimeClient + */ -use Aviat\AnimeClient\Model\API; +namespace Aviat\AnimeClient\API\MAL; + +use Aviat\AnimeClient\API\MAL as M; +use Aviat\Ion\Di\ContainerAware; /** * MyAnimeList API Model */ -class Model extends API { +class Model { + + use ContainerAware; + use MALTrait; - /** - * Base url for Kitsu API - */ - protected $baseUrl = 'https://myanimelist.net/api/'; + public function createListItem(array $data): bool + { - /** - * Default settings for Guzzle - * @var array - */ - protected $connectionDefaults = []; + } - /** - * Get the access token from the Kitsu API - * - * @param string $username - * @param string $password - * @return bool|string - */ - public function authenticate(string $username, string $password) - { - $response = $this->post('account/', [ - 'body' => http_build_query([ - 'grant_type' => 'password', - 'username' => $username, - 'password' => $password - ]) - ]); + public function getListItem(string $listId): array + { - $info = $response->getBody(); + } - if (array_key_exists('access_token', $info)) { - // @TODO save token - return true; - } + public function updateListItem(array $data) + { - return false; - } + } + + public function deleteListItem(string $id): bool + { + + } } \ No newline at end of file diff --git a/src/API/MAL/Transformer/AnimeListTransformer.php b/src/API/MAL/Transformer/AnimeListTransformer.php new file mode 100644 index 00000000..881adaf5 --- /dev/null +++ b/src/API/MAL/Transformer/AnimeListTransformer.php @@ -0,0 +1,46 @@ + + * @copyright 2015 - 2017 Timothy J. Warren + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 4.0 + * @link https://github.com/timw4mail/HummingBirdAnimeClient + */ + +namespace Aviat\AnimeClient\API\MAL; + +use Aviat\Ion\Transformer\AbstractTransformer; + +/** + * Transformer for updating MAL List + */ +class AnimeListTransformer extends AbstractTransformer { + + public function transform($item) + { + $rewatching = 'false'; + if (array_key_exists('rewatching', $item) && $item['rewatching']) + { + $rewatching = 'true'; + } + + return [ + 'id' => $item['id'], + 'data' => [ + 'status' => $item['watching_status'], + 'rating' => $item['user_rating'], + 'rewatch_value' => (int) $rewatching, + 'times_rewatched' => $item['rewatched'], + 'comments' => $item['notes'], + 'episode' => $item['episodes_watched'] + ] + ]; + } +} \ No newline at end of file diff --git a/src/API/MAL/Transformer/MALToKitsuTransformer.php b/src/API/MAL/Transformer/MALToKitsuTransformer.php new file mode 100644 index 00000000..dc8fed17 --- /dev/null +++ b/src/API/MAL/Transformer/MALToKitsuTransformer.php @@ -0,0 +1,33 @@ + + * @copyright 2015 - 2017 Timothy J. Warren + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 4.0 + * @link https://github.com/timw4mail/HummingBirdAnimeClient + */ + +namespace Aviat\AnimeClient\API\MAL; + +use Aviat\Ion\Transformer\AbstractTransformer; + +class MALToKitsuTransformer extends AbstractTransformer { + + + public function transform($item) + { + + } + + public function untransform($item) + { + + } +} \ No newline at end of file diff --git a/src/Controller.php b/src/Controller.php index d776873f..708e1984 100644 --- a/src/Controller.php +++ b/src/Controller.php @@ -304,7 +304,8 @@ class Controller { return $this->session_redirect(); } - $this->login("Invalid username or password."); + $this->set_flash_message('Invalid username or password.'); + $this->redirect($this->urlGenerator->url('login'), 303); } /** diff --git a/src/Util.php b/src/Util.php index e4743034..ac038b45 100644 --- a/src/Util.php +++ b/src/Util.php @@ -16,7 +16,6 @@ namespace Aviat\AnimeClient; -use abeautifulsite\SimpleImage; use Aviat\Ion\ConfigInterface; use Aviat\Ion\Di\{ContainerAware, ContainerInterface}; use DomainException; diff --git a/tests/API/JsonAPITest.php b/tests/API/JsonAPITest.php new file mode 100644 index 00000000..396d1ade --- /dev/null +++ b/tests/API/JsonAPITest.php @@ -0,0 +1,48 @@ + + * @copyright 2015 - 2017 Timothy J. Warren + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 4.0 + * @link https://github.com/timw4mail/HummingBirdAnimeClient + */ + +namespace Aviat\AnimeClient\Tests\API; + +use Aviat\AnimeClient\API\JsonAPI; +use Aviat\Ion\Json; +use PHPUnit\Framework\TestCase; + +class JsonAPITest extends TestCase { + + public function setUp() + { + $dir = __DIR__ . '/../test_data/JsonAPI'; + $this->startData = Json::decodeFile("{$dir}/jsonApiExample.json"); + $this->organizedIncludes = Json::decodeFile("{$dir}/organizedIncludes.json"); + $this->inlineIncluded = Json::decodeFile("{$dir}/inlineIncluded.json"); + } + + public function testOrganizeIncludes() + { + $expected = $this->organizedIncludes; + $actual = JsonAPI::organizeIncludes($this->startData['included']); + + $this->assertEquals($expected, $actual); + } + + public function testInlineIncludedRelationships() + { + $expected = $this->inlineIncluded; + $actual = JsonAPI::inlineIncludedRelationships($this->organizedIncludes, 'anime'); + + $this->assertEquals($expected, $actual); + } +} \ No newline at end of file diff --git a/tests/API/Kitsu/Transformer/AnimeListTransformerTest.php b/tests/API/Kitsu/Transformer/AnimeListTransformerTest.php new file mode 100644 index 00000000..18cc3803 --- /dev/null +++ b/tests/API/Kitsu/Transformer/AnimeListTransformerTest.php @@ -0,0 +1,90 @@ +beforeTransform = Json::decodeFile("{$dir}/animeListItemBeforeTransform.json"); + $this->afterTransform = Json::decodeFile("{$dir}/animeListItemAfterTransform.json"); + + $this->transformer = new AnimeListTransformer(); + } + + public function testTransform() + { + $expected = $this->afterTransform; + $actual = $this->transformer->transform($this->beforeTransform); + + $this->assertEquals($expected, $actual); + } + + public function dataUntransform() + { + return [[ + 'input' => [ + 'id' => 14047981, + 'watching_status' => 'current', + 'user_rating' => 8, + 'episodes_watched' => 38, + 'rewatched' => 0, + 'notes' => 'Very formulaic.', + 'edit' => true + ], + 'expected' => [ + 'id' => 14047981, + 'data' => [ + 'status' => 'current', + 'rating' => 4, + 'reconsuming' => false, + 'reconsumeCount' => 0, + 'notes' => 'Very formulaic.', + 'progress' => 38, + 'private' => false + ] + ] + ], [ + 'input' => [ + 'id' => 14047981, + 'watching_status' => 'current', + 'user_rating' => 8, + 'episodes_watched' => 38, + 'rewatched' => 0, + 'notes' => 'Very formulaic.', + 'edit' => 'true', + 'private' => 'On', + 'rewatching' => 'On' + ], + 'expected' => [ + 'id' => 14047981, + 'data' => [ + 'status' => 'current', + 'rating' => 4, + 'reconsuming' => true, + 'reconsumeCount' => 0, + 'notes' => 'Very formulaic.', + 'progress' => 38, + 'private' => true, + ] + ] + ]]; + } + + /** + * @dataProvider dataUntransform + */ + public function testUntransform($input, $expected) + { + $actual = $this->transformer->untransform($input); + $this->assertEquals($expected, $actual); + } +} \ No newline at end of file diff --git a/tests/API/Kitsu/Transformer/AnimeTransformerTest.php b/tests/API/Kitsu/Transformer/AnimeTransformerTest.php new file mode 100644 index 00000000..b72eb2e1 --- /dev/null +++ b/tests/API/Kitsu/Transformer/AnimeTransformerTest.php @@ -0,0 +1,30 @@ +beforeTransform = Json::decodeFile("{$dir}/animeBeforeTransform.json"); + //$this->afterTransform = Json::decodeFile("{$dir}/animeAfterTransform.json"); + + $this->transformer = new AnimeTransformer(); + } + + public function testTransform() + { + /*$expected = $this->afterTransform; + $actual = $this->transformer->transform($this->beforeTransform); + + $this->assertEquals($expected, $actual);*/ + } +} \ No newline at end of file diff --git a/tests/API/XMLTest.php b/tests/API/XMLTest.php index 50cebb37..b14d3f5b 100644 --- a/tests/API/XMLTest.php +++ b/tests/API/XMLTest.php @@ -1,18 +1,4 @@ - * @copyright 2015 - 2017 Timothy J. Warren - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @version 4.0 - * @link https://github.com/timw4mail/HummingBirdAnimeClient - */ namespace Aviat\AnimeClient\Tests\API; @@ -23,8 +9,8 @@ class XMLTest extends TestCase { public function setUp() { - $this->xml = file_get_contents(__DIR__ . '/../test_data/xmlTestFile.xml'); - $this->expectedXml = file_get_contents(__DIR__ . '/../test_data/minifiedXmlTestFile.xml'); + $this->xml = file_get_contents(__DIR__ . '/../test_data/XML/xmlTestFile.xml'); + $this->expectedXml = file_get_contents(__DIR__ . '/../test_data/XML/minifiedXmlTestFile.xml'); $this->array = [ 'entry' => [ diff --git a/tests/AnimeClient_TestCase.php b/tests/AnimeClient_TestCase.php index d565c738..76cfc0c3 100644 --- a/tests/AnimeClient_TestCase.php +++ b/tests/AnimeClient_TestCase.php @@ -7,8 +7,11 @@ use GuzzleHttp\Client; use GuzzleHttp\Handler\MockHandler; use GuzzleHttp\HandlerStack; use GuzzleHttp\Psr7\Response; -use Zend\Diactoros\Response as HttpResponse; -use Zend\Diactoros\ServerRequestFactory; +use PHPUnit\Framework\TestCase; +use Zend\Diactoros\{ + Response as HttpResponse, + ServerRequestFactory +}; define('ROOT_DIR', __DIR__ . '/../'); define('TEST_DATA_DIR', __DIR__ . '/test_data'); @@ -17,7 +20,7 @@ define('TEST_VIEW_DIR', __DIR__ . '/test_views'); /** * Base class for TestCases */ -class AnimeClient_TestCase extends PHPUnit_Framework_TestCase { +class AnimeClient_TestCase extends TestCase { // Test directory constants const ROOT_DIR = ROOT_DIR; const SRC_DIR = AnimeClient::SRC_DIR; diff --git a/tests/ControllerTest.php b/tests/ControllerTest.php index 8c0e3a6e..b63b3598 100644 --- a/tests/ControllerTest.php +++ b/tests/ControllerTest.php @@ -1,10 +1,12 @@ -