Version 5.1 - All the GraphQL #32

Closed
timw4mail wants to merge 1160 commits from develop into master
22 changed files with 1420 additions and 160 deletions
Showing only changes of commit d3cbe06cb0 - Show all commits

View File

@ -13,7 +13,7 @@
</th> </th>
<th> <th>
<article class="media"> <article class="media">
<?= $helper->img($item['cover_image']); ?> <?= $helper->img($urlGenerator->assetUrl("images/anime/{$item['hummingbird_id']}.jpg")); ?>
</article> </article>
</th> </th>
</tr> </tr>

View File

@ -393,12 +393,12 @@ class DoubleQuoteUsageSniff extends VariableUsageSniff
&& false === $smpl_qt_at && false === $smpl_qt_at
) { ) {
$error = 'Single-quoted strings should be used unless it contains variables, special chars like \n or single quotes.'; $error = 'Single-quoted strings should be used unless it contains variables, special chars like \n or single quotes.';
$phpcsFile->addError($error, $stackPtr); $phpcsFile->addError($error, $stackPtr, 111);
} else if (false !== $smpl_qt_at && false !== $dbl_qt_at } else if (false !== $smpl_qt_at && false !== $dbl_qt_at
&& false === $has_variable && false === $has_specific_sequence && false === $has_variable && false === $has_specific_sequence
) { ) {
$warning = 'It is encouraged to use a single-quoted string, since it doesn\'t contain any variable nor special char though it mixes single and double quotes.'; $warning = 'It is encouraged to use a single-quoted string, since it doesn\'t contain any variable nor special char though it mixes single and double quotes.';
$phpcsFile->addWarning($warning, $stackPtr); $phpcsFile->addWarning($warning, $stackPtr, 222);
} }
}//end processDoubleQuotedString() }//end processDoubleQuotedString()
@ -426,7 +426,7 @@ class DoubleQuoteUsageSniff extends VariableUsageSniff
$smpl_qt_at = strpos($qtString, "'"); $smpl_qt_at = strpos($qtString, "'");
if (false === $has_variable && false !== $smpl_qt_at && false === $dbl_qt_at) { if (false === $has_variable && false !== $smpl_qt_at && false === $dbl_qt_at) {
$warning = 'You may also use double-quoted strings if the string contains single quotes, so you do not have to use escape characters.'; $warning = 'You may also use double-quoted strings if the string contains single quotes, so you do not have to use escape characters.';
$phpcsFile->addWarning($warning, $stackPtr); $phpcsFile->addWarning($warning, $stackPtr, 333);
} }
}//end processSingleQuotedString() }//end processSingleQuotedString()

View File

@ -17,7 +17,7 @@
} }
}, },
"require": { "require": {
"amphp/artax": "^2.0", "amphp/artax": "^3.0",
"aura/html": "^2.0", "aura/html": "^2.0",
"aura/router": "^3.0", "aura/router": "^3.0",
"aura/session": "^2.0", "aura/session": "^2.0",
@ -42,7 +42,9 @@
"sebastian/phpcpd": "^3.0", "sebastian/phpcpd": "^3.0",
"spatie/phpunit-snapshot-assertions": "^1.2.0", "spatie/phpunit-snapshot-assertions": "^1.2.0",
"squizlabs/php_codesniffer": "^3.0.0@beta", "squizlabs/php_codesniffer": "^3.0.0@beta",
"theseer/phpdox": "^0.10.1" "symfony/var-dumper": "^4.0.1",
"theseer/phpdox": "^0.10.1",
"filp/whoops": "^2.1"
}, },
"scripts": { "scripts": {
"build": "vendor/bin/robo build", "build": "vendor/bin/robo build",

View File

@ -28,6 +28,10 @@ if ($timezone === '' || $timezone === FALSE)
// Load composer autoloader // Load composer autoloader
require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/vendor/autoload.php';
$whoops = new \Whoops\Run;
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
$whoops->register();
// Define base directories // Define base directories
$APP_DIR = _dir(__DIR__, 'app'); $APP_DIR = _dir(__DIR__, 'app');
$APPCONF_DIR = _dir($APP_DIR, 'appConf'); $APPCONF_DIR = _dir($APP_DIR, 'appConf');

View File

@ -16,8 +16,9 @@
namespace Aviat\EasyMin; namespace Aviat\EasyMin;
use function Amp\wait; use function Amp\Promise\wait;
use Amp\Artax\{Client, FormBody, Request}; use Amp\Artax\Request;
use Aviat\AnimeClient\API\HummingbirdClient;
use Aviat\Ion\{Json, JsonException}; use Aviat\Ion\{Json, JsonException};
// Include Amp and Artax // Include Amp and Artax
@ -113,24 +114,24 @@ class JSMin {
* Makes a call to google closure compiler service * Makes a call to google closure compiler service
* *
* @param array $options - Form parameters * @param array $options - Form parameters
* @throws \TypeError
* @return object * @return object
*/ */
protected function closureCall(array $options) protected function closureCall(array $options)
{ {
$formFields = http_build_query($options); $formFields = http_build_query($options);
$request = (new Request) $request = (new Request('https://closure-compiler.appspot.com/compile'))
->setMethod('POST') ->withMethod('POST')
->setUri('https://closure-compiler.appspot.com/compile') ->withHeaders([
->setAllHeaders([
'Accept' => 'application/json', 'Accept' => 'application/json',
'Accept-Encoding' => 'gzip', 'Accept-Encoding' => 'gzip',
'Content-type' => 'application/x-www-form-urlencoded' 'Content-type' => 'application/x-www-form-urlencoded'
]) ])
->setBody($formFields); ->withBody($formFields);
$response = wait((new Client)->request($request, [ $response = wait((new HummingbirdClient)->request($request, [
Client::OP_AUTO_ENCODING => false HummingbirdClient::OP_AUTO_ENCODING => false
])); ]));
return $response; return $response;
@ -147,7 +148,7 @@ class JSMin {
try try
{ {
$errorRes = $this->closureCall($options); $errorRes = $this->closureCall($options);
$errorJson = $errorRes->getBody(); $errorJson = wait($errorRes->getBody());
$errorObj = Json::decode($errorJson) ?: (object)[]; $errorObj = Json::decode($errorJson) ?: (object)[];
@ -237,7 +238,7 @@ class JSMin {
// Now actually retrieve the compiled code // Now actually retrieve the compiled code
$options['output_info'] = 'compiled_code'; $options['output_info'] = 'compiled_code';
$res = $this->closureCall($options); $res = $this->closureCall($options);
$json = $res->getBody(); $json = wait($res->getBody());
$obj = Json::decode($json); $obj = Json::decode($json);
//return $obj; //return $obj;

View File

@ -16,6 +16,8 @@
namespace Aviat\AnimeClient\API; namespace Aviat\AnimeClient\API;
use function Amp\Promise\wait;
use Amp; use Amp;
use Amp\Artax\{FormBody, Request}; use Amp\Artax\{FormBody, Request};
use Aviat\Ion\Json; use Aviat\Ion\Json;
@ -23,7 +25,7 @@ use InvalidArgumentException;
use Psr\Log\LoggerAwareTrait; use Psr\Log\LoggerAwareTrait;
/** /**
* Wrapper around Artex to make it easier to build API requests * Wrapper around Artax to make it easier to build API requests
*/ */
class APIRequestBuilder { class APIRequestBuilder {
use LoggerAwareTrait; use LoggerAwareTrait;
@ -60,7 +62,7 @@ class APIRequestBuilder {
/** /**
* The current request * The current request
* @var \Amp\Promise * @var \Amp\Artax\Request
*/ */
protected $request; protected $request;
@ -96,11 +98,12 @@ class APIRequestBuilder {
* Set the request body * Set the request body
* *
* @param FormBody|string $body * @param FormBody|string $body
* @throws \TypeError
* @return self * @return self
*/ */
public function setBody($body): self public function setBody($body): self
{ {
$this->request->setBody($body); $this->request = $this->request->withBody($body);
return $this; return $this;
} }
@ -108,13 +111,26 @@ class APIRequestBuilder {
* Set body as form fields * Set body as form fields
* *
* @param array $fields Mapping of field names to values * @param array $fields Mapping of field names to values
* @throws \TypeError
* @return self * @return self
*/ */
public function setFormFields(array $fields): self public function setFormFields(array $fields): self
{ {
$this->setHeader("Content-Type", "application/x-www-form-urlencoded"); $body = new FormBody();
$body = (new FormBody)->addFields($fields); $body->addFields($fields);
$this->setBody($body);
return $this->setBody($body);
}
/**
* Unset a request header
*
* @param string $name
* @return self
*/
public function unsetHeader(string $name): self
{
$this->request = $this->request->withoutHeader($name);
return $this; return $this;
} }
@ -125,9 +141,17 @@ class APIRequestBuilder {
* @param string $value * @param string $value
* @return self * @return self
*/ */
public function setHeader(string $name, string $value): self public function setHeader(string $name, string $value = NULL): self
{ {
$this->request->setHeader($name, $value); if (NULL === $value)
{
$this->unsetHeader($name);
}
else
{
$this->request = $this->request->withHeader($name, $value);
}
return $this; return $this;
} }
@ -153,6 +177,7 @@ class APIRequestBuilder {
* Set the request body * Set the request body
* *
* @param mixed $body * @param mixed $body
* @throws \TypeError
* @return self * @return self
*/ */
public function setJsonBody($body): self public function setJsonBody($body): self
@ -160,7 +185,7 @@ class APIRequestBuilder {
$requestBody = ( ! is_scalar($body)) $requestBody = ( ! is_scalar($body))
? Json::encode($body) ? Json::encode($body)
: $body; : $body;
return $this->setBody($requestBody); return $this->setBody($requestBody);
} }
@ -179,9 +204,10 @@ class APIRequestBuilder {
/** /**
* Return the promise for the current request * Return the promise for the current request
* *
* @return \Amp\Promise * @throws \Throwable
* @return \Amp\Artax\Request
*/ */
public function getFullRequest() public function getFullRequest(): Request
{ {
$this->buildUri(); $this->buildUri();
@ -189,8 +215,12 @@ class APIRequestBuilder {
{ {
$this->logger->debug('API Request', [ $this->logger->debug('API Request', [
'request_url' => $this->request->getUri(), 'request_url' => $this->request->getUri(),
'request_headers' => $this->request->getAllHeaders(), 'request_headers' => $this->request->getHeaders(),
'request_body' => $this->request->getBody() 'request_body' => wait(
$this->request->getBody()
->createBodyStream()
->read()
)
]); ]);
} }
@ -207,19 +237,21 @@ class APIRequestBuilder {
*/ */
public function newRequest(string $type, string $uri): self public function newRequest(string $type, string $uri): self
{ {
if ( ! in_array($type, $this->validMethods)) if ( ! \in_array($type, $this->validMethods, TRUE))
{ {
throw new InvalidArgumentException('Invalid HTTP methods'); throw new InvalidArgumentException('Invalid HTTP method');
} }
$this->resetState(); $realUrl = (strpos($uri, '//') !== FALSE)
? $uri
$this->request : $this->baseUrl . $uri;
->setMethod($type)
->setProtocol('1.1');
$this->resetState($realUrl, $type);
$this->path = $uri; $this->path = $uri;
// Actually create the full url!
$this->buildUri();
if ( ! empty($this->defaultHeaders)) if ( ! empty($this->defaultHeaders))
{ {
$this->setHeaders($this->defaultHeaders); $this->setHeaders($this->defaultHeaders);
@ -231,9 +263,9 @@ class APIRequestBuilder {
/** /**
* Create the full request url * Create the full request url
* *
* @return void * @return Request
*/ */
private function buildUri() private function buildUri(): Request
{ {
$url = (strpos($this->path, '//') !== FALSE) $url = (strpos($this->path, '//') !== FALSE)
? $this->path ? $this->path
@ -244,18 +276,25 @@ class APIRequestBuilder {
$url .= '?' . $this->query; $url .= '?' . $this->query;
} }
$this->request->setUri($url); $this->request = $this->request->withUri($url);
return $this->request;
} }
/** /**
* Reset the class state for a new request * Reset the class state for a new request
* *
* @param string $url
* @param string $type
* @return void * @return void
*/ */
private function resetState() private function resetState($url, $type = 'GET')
{ {
$requestUrl = $url ?: $this->baseUrl;
$this->path = ''; $this->path = '';
$this->query = ''; $this->query = '';
$this->request = new Request(); $this->request = (new Request($requestUrl))
->withMethod($type);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -73,14 +73,14 @@ class Auth {
$config = $this->container->get('config'); $config = $this->container->get('config');
$username = $config->get(['kitsu_username']); $username = $config->get(['kitsu_username']);
try // try
{ {
$auth = $this->model->authenticate($username, $password); $auth = $this->model->authenticate($username, $password);
} }
catch (Exception $e) /* catch (Exception $e)
{ {
return FALSE; return FALSE;
} }*/
if (FALSE !== $auth) if (FALSE !== $auth)

View File

@ -16,10 +16,7 @@
namespace Aviat\AnimeClient\API\Kitsu; namespace Aviat\AnimeClient\API\Kitsu;
use Aviat\AnimeClient\API\{ use Aviat\AnimeClient\API\APIRequestBuilder;
APIRequestBuilder,
Kitsu as K
};
class KitsuRequestBuilder extends APIRequestBuilder { class KitsuRequestBuilder extends APIRequestBuilder {
@ -27,7 +24,7 @@ class KitsuRequestBuilder extends APIRequestBuilder {
* The base url for api requests * The base url for api requests
* @var string $base_url * @var string $base_url
*/ */
protected $baseUrl = "https://kitsu.io/api/edge/"; protected $baseUrl = 'https://kitsu.io/api/edge/';
/** /**
* HTTP headers to send with every request * HTTP headers to send with every request
@ -36,9 +33,9 @@ class KitsuRequestBuilder extends APIRequestBuilder {
*/ */
protected $defaultHeaders = [ protected $defaultHeaders = [
'User-Agent' => "Tim's Anime Client/4.0", 'User-Agent' => "Tim's Anime Client/4.0",
'Accept-Encoding' => 'application/vnd.api+json', 'Accept' => 'application/vnd.api+json',
'Content-Type' => 'application/vnd.api+json', 'Content-Type' => 'application/vnd.api+json',
'client_id' => 'dd031b32d2f56c990b1425efe6c42ad847e7fe3ab46bf1299f05ecd856bdb7dd', 'CLIENT_ID' => 'dd031b32d2f56c990b1425efe6c42ad847e7fe3ab46bf1299f05ecd856bdb7dd',
'client_secret' => '54d7307928f63414defd96399fc31ba847961ceaecef3a5fd93144e960c0e151', 'CLIENT_SECRET' => '54d7307928f63414defd96399fc31ba847961ceaecef3a5fd93144e960c0e151',
]; ];
} }

View File

@ -18,12 +18,17 @@ namespace Aviat\AnimeClient\API\Kitsu;
use const Aviat\AnimeClient\SESSION_SEGMENT; use const Aviat\AnimeClient\SESSION_SEGMENT;
use function Amp\wait; use function Amp\Promise\wait;
use Amp\Artax\{Client, Request}; use Amp\Artax\Request;
use Aviat\AnimeClient\AnimeClient; use Aviat\AnimeClient\AnimeClient;
use Aviat\AnimeClient\API\{FailedResponseException, Kitsu as K}; use Aviat\AnimeClient\API\{
FailedResponseException,
HummingbirdClient,
Kitsu as K
};
use Aviat\Ion\Json; use Aviat\Ion\Json;
use Aviat\Ion\JsonException;
trait KitsuTrait { trait KitsuTrait {
@ -80,24 +85,29 @@ trait KitsuTrait {
$token = $cacheItem->get(); $token = $cacheItem->get();
} }
if ( ! is_null($token)) if (NULL !== $token)
{ {
$request = $request->setAuth('bearer', $token); $request = $request->setAuth('bearer', $token);
} }
if (array_key_exists('form_params', $options)) if (array_key_exists('form_params', $options))
{ {
$request->setFormFields($options['form_params']); $request = $request->setFormFields($options['form_params']);
} }
if (array_key_exists('query', $options)) if (array_key_exists('query', $options))
{ {
$request->setQuery($options['query']); $request = $request->setQuery($options['query']);
} }
if (array_key_exists('body', $options)) if (array_key_exists('body', $options))
{ {
$request->setJsonBody($options['body']); $request = $request->setJsonBody($options['body']);
}
if (array_key_exists('headers', $options))
{
$request = $request->setHeaders($options['headers']);
} }
return $request->getFullRequest(); return $request->getFullRequest();
@ -113,9 +123,24 @@ trait KitsuTrait {
*/ */
private function getResponse(string $type, string $url, array $options = []) private function getResponse(string $type, string $url, array $options = [])
{ {
$logger = NULL;
if ($this->getContainer())
{
$logger = $this->container->getLogger('kitsu-request');
}
$request = $this->setUpRequest($type, $url, $options); $request = $this->setUpRequest($type, $url, $options);
$response = wait((new Client)->request($request)); $response = wait((new HummingbirdClient)->request($request));
if ($logger)
{
$logger->debug('Kitsu API Response', [
'response_status' => $response->getStatus(),
'request_headers' => $response->getOriginalRequest()->getHeaders(),
'response_headers' => $response->getHeaders()
]);
}
return $response; return $response;
} }
@ -126,6 +151,8 @@ trait KitsuTrait {
* @param string $type * @param string $type
* @param string $url * @param string $url
* @param array $options * @param array $options
* @throws \Aviat\Ion\JsonException
* @throws FailedResponseException
* @return array * @return array
*/ */
private function request(string $type, string $url, array $options = []): array private function request(string $type, string $url, array $options = []): array
@ -148,7 +175,16 @@ trait KitsuTrait {
throw new FailedResponseException('Failed to get the proper response from the API'); throw new FailedResponseException('Failed to get the proper response from the API');
} }
return Json::decode($response->getBody(), TRUE); try
{
return Json::decode(wait($response->getBody()), TRUE);
}
catch (JsonException $e)
{
print_r($e);
die();
}
} }
/** /**
@ -198,7 +234,7 @@ trait KitsuTrait {
} }
} }
return JSON::decode($response->getBody(), TRUE); return JSON::decode(wait($response->getBody()), TRUE);
} }
/** /**

View File

@ -18,8 +18,10 @@ namespace Aviat\AnimeClient\API\Kitsu;
use const Aviat\AnimeClient\SESSION_SEGMENT; use const Aviat\AnimeClient\SESSION_SEGMENT;
use function Amp\Promise\wait;
use Amp\Artax\Request; use Amp\Artax\Request;
use Aviat\AnimeClient\API\AbstractListItem; use Aviat\AnimeClient\API\{AbstractListItem, HummingbirdClient};
use Aviat\Ion\Di\ContainerAware; use Aviat\Ion\Di\ContainerAware;
use Aviat\Ion\Json; use Aviat\Ion\Json;
use RuntimeException; use RuntimeException;
@ -113,21 +115,21 @@ class ListItem extends AbstractListItem {
public function get(string $id): array public function get(string $id): array
{ {
$authHeader = $this->getAuthHeader(); $authHeader = $this->getAuthHeader();
$request = $this->requestBuilder->newRequest('GET', "library-entries/{$id}") $request = $this->requestBuilder->newRequest('GET', "library-entries/{$id}")
->setQuery([ ->setQuery([
'include' => 'media,media.genres,media.mappings' 'include' => 'media,media.genres,media.mappings'
]); ]);
if ($authHeader !== FALSE) if ($authHeader !== FALSE)
{ {
$request = $request->setHeader('Authorization', $authHeader); $request = $request->setHeader('Authorization', $authHeader);
} }
$request = $request->getFullRequest(); $request = $request->getFullRequest();
$response = \Amp\wait((new \Amp\Artax\Client)->request($request)); $response = wait((new HummingbirdClient)->request($request));
return Json::decode($response->getBody()); return Json::decode(wait($response->getBody()));
} }
public function update(string $id, array $data): Request public function update(string $id, array $data): Request
@ -140,15 +142,15 @@ class ListItem extends AbstractListItem {
'attributes' => $data 'attributes' => $data
] ]
]; ];
$request = $this->requestBuilder->newRequest('PATCH', "library-entries/{$id}") $request = $this->requestBuilder->newRequest('PATCH', "library-entries/{$id}")
->setJsonBody($requestData); ->setJsonBody($requestData);
if ($authHeader !== FALSE) if ($authHeader !== FALSE)
{ {
$request = $request->setHeader('Authorization', $authHeader); $request = $request->setHeader('Authorization', $authHeader);
} }
return $request->getFullRequest(); return $request->getFullRequest();
} }
} }

View File

@ -16,9 +16,9 @@
namespace Aviat\AnimeClient\API\Kitsu; namespace Aviat\AnimeClient\API\Kitsu;
use function Amp\{all, wait}; use function Amp\Promise\wait;
use Amp\Artax\{Client, Request}; use Amp\Artax\Request;
use Aviat\AnimeClient\API\{ use Aviat\AnimeClient\API\{
CacheTrait, CacheTrait,
JsonAPI, JsonAPI,
@ -101,22 +101,37 @@ class Model {
*/ */
public function authenticate(string $username, string $password) public function authenticate(string $username, string $password)
{ {
// K::AUTH_URL
$response = $this->getResponse('POST', K::AUTH_URL, [ $response = $this->getResponse('POST', K::AUTH_URL, [
'headers' => [], 'headers' => [
'accept' => NULL,
'Content-type' => 'application/x-www-form-urlencoded',
'client_id' => NULL,
'client_secret' => NULL
],
'form_params' => [ 'form_params' => [
'grant_type' => 'password', 'grant_type' => 'password',
'username' => $username, 'username' => $username,
'password' => $password 'password' => $password
] ]
]); ]);
$data = Json::decode(wait($response->getBody()));
$data = Json::decode((string)$response->getBody());
//dump($response);
if (array_key_exists('access_token', $data)) if (array_key_exists('access_token', $data))
{ {
return $data; return $data;
} }
if (array_key_exists('error', $data))
{
dump($data['error']);
dump($response);
die();
//throw new \Exception('auth error');
}
return FALSE; return FALSE;
} }
@ -129,14 +144,17 @@ class Model {
public function reAuthenticate(string $token) public function reAuthenticate(string $token)
{ {
$response = $this->getResponse('POST', K::AUTH_URL, [ $response = $this->getResponse('POST', K::AUTH_URL, [
'headers' => [], 'headers' => [
'Accept-encoding' => '*'
],
'form_params' => [ 'form_params' => [
'grant_type' => 'refresh_token', 'grant_type' => 'refresh_token',
'refresh_token' => $token 'refresh_token' => $token
] ]
]); ]);
$data = Json::decode((string)$response->getBody()); $data = Json::decode(wait($response->getBody()));
if (array_key_exists('access_token', $data)) if (array_key_exists('access_token', $data))
{ {
@ -186,7 +204,7 @@ class Model {
*/ */
public function getCharacter(string $slug): array public function getCharacter(string $slug): array
{ {
$data = $this->getRequest('/characters', [ $data = $this->getRequest('characters', [
'query' => [ 'query' => [
'filter' => [ 'filter' => [
'slug' => $slug, 'slug' => $slug,
@ -211,7 +229,7 @@ class Model {
public function getUserData(string $username): array public function getUserData(string $username): array
{ {
// $userId = $this->getUserIdByUsername($username); // $userId = $this->getUserIdByUsername($username);
$data = $this->getRequest("/users", [ $data = $this->getRequest("users", [
'query' => [ 'query' => [
'filter' => [ 'filter' => [
'name' => $username, 'name' => $username,
@ -425,7 +443,7 @@ class Model {
foreach($responses as $response) foreach($responses as $response)
{ {
$data = Json::decode($response->getBody()); $data = Json::decode($response);
$output = array_merge_recursive($output, $data); $output = array_merge_recursive($output, $data);
} }
@ -522,7 +540,6 @@ class Model {
*/ */
public function getRawAnimeList(string $status): array public function getRawAnimeList(string $status): array
{ {
$options = [ $options = [
'filter' => [ 'filter' => [
'user_id' => $this->getUserIdByUsername($this->getUsername()), 'user_id' => $this->getUserIdByUsername($this->getUsername()),
@ -689,7 +706,7 @@ class Model {
foreach($responses as $response) foreach($responses as $response)
{ {
$data = Json::decode($response->getBody()); $data = Json::decode($response);
$output = array_merge_recursive($output, $data); $output = array_merge_recursive($output, $data);
} }

View File

@ -94,9 +94,9 @@ class ListItem {
$config = $this->container->get('config'); $config = $this->container->get('config');
$xml = XML::toXML(['entry' => $data]); $xml = XML::toXML(['entry' => $data]);
$body = (new FormBody) $body = new FormBody();
->addField('id', $id) $body->addField('id', $id);
->addField('data', $xml); $body->addField('data', $xml);
return $this->requestBuilder->newRequest('POST', "{$type}list/update/{$id}.xml") return $this->requestBuilder->newRequest('POST', "{$type}list/update/{$id}.xml")
->setFormFields([ ->setFormFields([

View File

@ -16,15 +16,13 @@
namespace Aviat\AnimeClient\API\MAL; namespace Aviat\AnimeClient\API\MAL;
use Amp\Artax\{Client, FormBody, Request}; use function Amp\Promise\wait;
use Aviat\AnimeClient\API\{ use Aviat\AnimeClient\API\{
HummingbirdClient,
MAL as M, MAL as M,
APIRequestBuilder,
XML XML
}; };
use Aviat\AnimeClient\API\MALRequestBuilder;
use Aviat\Ion\Json;
use InvalidArgumentException;
trait MALTrait { trait MALTrait {
@ -82,12 +80,12 @@ trait MALTrait {
if (array_key_exists('query', $options)) if (array_key_exists('query', $options))
{ {
$request->setQuery($options['query']); $request = $request->setQuery($options['query']);
} }
if (array_key_exists('body', $options)) if (array_key_exists('body', $options))
{ {
$request->setBody($options['body']); $request = $request->setBody($options['body']);
} }
return $request->getFullRequest(); return $request->getFullRequest();
@ -110,14 +108,14 @@ trait MALTrait {
} }
$request = $this->setUpRequest($type, $url, $options); $request = $this->setUpRequest($type, $url, $options);
$response = \Amp\wait((new Client)->request($request)); $response = wait((new HummingbirdClient)->request($request));
$logger->debug('MAL api response', [ $logger->debug('MAL api response', [
'status' => $response->getStatus(), 'status' => $response->getStatus(),
'reason' => $response->getReason(), 'reason' => $response->getReason(),
'body' => $response->getBody(), 'body' => $response->getBody(),
'headers' => $response->getAllHeaders(), 'headers' => $response->getHeaders(),
'requestHeaders' => $request->getAllHeaders(), 'requestHeaders' => $request->getHeaders(),
]); ]);
return $response; return $response;
@ -149,7 +147,7 @@ trait MALTrait {
} }
} }
return XML::toArray((string) $response->getBody()); return XML::toArray(wait($response->getBody()));
} }
/** /**

View File

@ -16,21 +16,21 @@
namespace Aviat\AnimeClient\API; namespace Aviat\AnimeClient\API;
use Amp; use function Amp\call;
use Amp\Artax\Client; use function Amp\Promise\{all, wait};
/** /**
* Class to simplify making and validating simultaneous requests * Class to simplify making and validating simultaneous requests
*/ */
class ParallelAPIRequest { class ParallelAPIRequest {
/** /**
* Set of requests to make in parallel * Set of requests to make in parallel
* *
* @var array * @var array
*/ */
protected $requests = []; protected $requests = [];
/** /**
* Add a request * Add a request
* *
@ -45,11 +45,11 @@ class ParallelAPIRequest {
$this->requests[$key] = $request; $this->requests[$key] = $request;
return $this; return $this;
} }
$this->requests[] = $request; $this->requests[] = $request;
return $this; return $this;
} }
/** /**
* Add multiple requests * Add multiple requests
* *
@ -61,22 +61,27 @@ class ParallelAPIRequest {
array_walk($requests, [$this, 'addRequest']); array_walk($requests, [$this, 'addRequest']);
return $this; return $this;
} }
/** /**
* Actually make the requests * Actually make the requests
* *
* @param bool $allowFailingRequests * @return array
* @return array
*/ */
public function makeRequests(bool $allowFailingRequests = FALSE): array public function makeRequests(): array
{ {
$client = new Client(); $client = new HummingbirdClient();
$promises = $client->requestMulti($this->requests); $promises = [];
$func = ($allowFailingRequests) ? '\Amp\some' : '\Amp\all'; foreach ($this->requests as $key => $url)
{
$results = Amp\wait($func($promises)); $promises[$key] = call(function () use ($client, $url) {
$response = yield $client->request($url);
return $results; $body = yield $response->getBody();
return $body;
});
}
return wait(all($promises));
} }
} }

View File

@ -21,7 +21,6 @@ use Aviat\AnimeClient\Model\{
Anime as AnimeModel, Anime as AnimeModel,
AnimeCollection as AnimeCollectionModel AnimeCollection as AnimeCollectionModel
}; };
use Aviat\AnimeClient\UrlGenerator;
use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\ContainerInterface;
/** /**

View File

@ -16,11 +16,10 @@
namespace Aviat\AnimeClient\Controller; namespace Aviat\AnimeClient\Controller;
use function Amp\wait; use function Amp\Promise\wait;
use Amp\Artax\Client;
use Aviat\AnimeClient\Controller as BaseController; use Aviat\AnimeClient\Controller as BaseController;
use Aviat\AnimeClient\API\JsonAPI; use Aviat\AnimeClient\API\{HummingbirdClient, JsonAPI};
use Aviat\Ion\View\HtmlView; use Aviat\Ion\View\HtmlView;
/** /**
@ -109,13 +108,17 @@ class Index extends BaseController {
$username = $this->config->get(['kitsu_username']); $username = $this->config->get(['kitsu_username']);
$model = $this->container->get('kitsu-model'); $model = $this->container->get('kitsu-model');
$data = $model->getUserData($username); $data = $model->getUserData($username);
$orgData = JsonAPI::organizeData($data); $orgData = JsonAPI::organizeData($data)[0];
$rels = $orgData['relationships'] ?? [];
$favorites = array_key_exists('favorites', $rels) ? $rels['favorites'] : [];
$this->outputHTML('me', [ $this->outputHTML('me', [
'title' => 'About ' . $this->config->get('whose_list'), 'title' => 'About ' . $this->config->get('whose_list'),
'data' => $orgData[0], 'data' => $orgData,
'attributes' => $orgData[0]['attributes'], 'attributes' => $orgData['attributes'],
'relationships' => $orgData[0]['relationships'], 'relationships' => $rels,
'favorites' => $this->organizeFavorites($orgData[0]['relationships']['favorites']), 'favorites' => $this->organizeFavorites($favorites),
]); ]);
} }
@ -151,14 +154,14 @@ class Index extends BaseController {
return; return;
} }
$promise = (new Client)->request($kitsuUrl); $promise = (new HummingbirdClient)->request($kitsuUrl);
$response = wait($promise); $response = wait($promise);
$data = (string) $response->getBody(); $data = wait($response->getBody());
$baseSavePath = $this->config->get('img_cache_path'); $baseSavePath = $this->config->get('img_cache_path');
file_put_contents("{$baseSavePath}/{$type}/{$id}.{$ext}", $data); file_put_contents("{$baseSavePath}/{$type}/{$id}.{$ext}", $data);
header('Content-type: ' . $response->getHeader('content-type')[0]); header('Content-type: ' . $response->getHeader('content-type')[0]);
echo (string) $response->getBody(); echo $data;
} }
private function organizeFavorites(array $rawfavorites): array private function organizeFavorites(array $rawfavorites): array

View File

@ -158,9 +158,9 @@ class Anime extends API {
$requester->addRequest($this->kitsuModel->createListItem($data), 'kitsu'); $requester->addRequest($this->kitsuModel->createListItem($data), 'kitsu');
$results = $requester->makeRequests(TRUE); $results = $requester->makeRequests();
return count($results[1]) > 0; return count($results) > 0;
} }
/** /**
@ -180,11 +180,13 @@ class Anime extends API {
$requester->addRequest($this->kitsuModel->updateListItem($data), 'kitsu'); $requester->addRequest($this->kitsuModel->updateListItem($data), 'kitsu');
$results = $requester->makeRequests(TRUE); $results = $requester->makeRequests();
$body = Json::decode($results['kitsu']);
$statusCode = (array_key_exists('error', $body)) ? 400: 200;
return [ return [
'body' => Json::decode($results[1]['kitsu']->getBody()), 'body' => Json::decode($results['kitsu']),
'statusCode' => $results[1]['kitsu']->getStatus() 'statusCode' => $statusCode
]; ];
} }
@ -206,8 +208,8 @@ class Anime extends API {
$requester->addRequest($this->kitsuModel->deleteListItem($id), 'kitsu'); $requester->addRequest($this->kitsuModel->deleteListItem($id), 'kitsu');
$results = $requester->makeRequests(TRUE); $results = $requester->makeRequests();
return count($results[1]) > 0; return count($results) > 0;
} }
} }

View File

@ -131,9 +131,9 @@ class Manga extends API
$requester->addRequest($this->kitsuModel->createListItem($data), 'kitsu'); $requester->addRequest($this->kitsuModel->createListItem($data), 'kitsu');
$results = $requester->makeRequests(TRUE); $results = $requester->makeRequests();
return count($results[1]) > 0; return count($results) > 0;
} }
/** /**
@ -153,11 +153,13 @@ class Manga extends API
$requester->addRequest($this->kitsuModel->updateListItem($data), 'kitsu'); $requester->addRequest($this->kitsuModel->updateListItem($data), 'kitsu');
$results = $requester->makeRequests(TRUE); $results = $requester->makeRequests();
$body = Json::decode($results['kitsu']);
$statusCode = (array_key_exists('error', $body)) ? 400: 200;
return [ return [
'body' => Json::decode($results[1]['kitsu']->getBody()), 'body' => Json::decode($results['kitsu']),
'statusCode' => $results[1]['kitsu']->getStatus() 'statusCode' => $statusCode
]; ];
} }
@ -179,9 +181,9 @@ class Manga extends API
$requester->addRequest($this->kitsuModel->deleteListItem($id), 'kitsu'); $requester->addRequest($this->kitsuModel->deleteListItem($id), 'kitsu');
$results = $requester->makeRequests(TRUE); $results = $requester->makeRequests();
return count($results[1]) > 0; return count($results) > 0;
} }
/** /**

View File

@ -16,15 +16,14 @@
namespace Aviat\AnimeClient\Tests\API; namespace Aviat\AnimeClient\Tests\API;
use Amp; use function Amp\Promise\wait;
use Amp\Artax\Client; use Aviat\AnimeClient\API\{APIRequestBuilder, HummingbirdClient};
use Aviat\AnimeClient\API\APIRequestBuilder;
use Aviat\Ion\Json; use Aviat\Ion\Json;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger; use Psr\Log\NullLogger;
class APIRequestBuilderTest extends TestCase { class APIRequestBuilderTest extends TestCase {
protected $builder; protected $builder;
public function setUp() public function setUp()
@ -42,8 +41,8 @@ class APIRequestBuilderTest extends TestCase {
{ {
$request = $this->builder->newRequest('GET', 'gzip') $request = $this->builder->newRequest('GET', 'gzip')
->getFullRequest(); ->getFullRequest();
$response = Amp\wait((new Client)->request($request)); $response = wait((new HummingbirdClient)->request($request));
$body = Json::decode($response->getBody()); $body = Json::decode(wait($response->getBody()));
$this->assertEquals(1, $body['gzipped']); $this->assertEquals(1, $body['gzipped']);
} }
@ -60,8 +59,8 @@ class APIRequestBuilderTest extends TestCase {
->setBasicAuth('username', 'password') ->setBasicAuth('username', 'password')
->getFullRequest(); ->getFullRequest();
$response = Amp\wait((new Client)->request($request)); $response = wait((new HummingbirdClient)->request($request));
$body = Json::decode($response->getBody()); $body = Json::decode(wait($response->getBody()));
$this->assertEquals('Basic dXNlcm5hbWU6cGFzc3dvcmQ=', $body['headers']['Authorization']); $this->assertEquals('Basic dXNlcm5hbWU6cGFzc3dvcmQ=', $body['headers']['Authorization']);
} }
@ -88,8 +87,8 @@ class APIRequestBuilderTest extends TestCase {
->setQuery($query) ->setQuery($query)
->getFullRequest(); ->getFullRequest();
$response = Amp\wait((new Client)->request($request)); $response = wait((new HummingbirdClient)->request($request));
$body = Json::decode($response->getBody()); $body = Json::decode(wait($response->getBody()));
$this->assertEquals($expected, $body['args']); $this->assertEquals($expected, $body['args']);
} }
@ -105,8 +104,8 @@ class APIRequestBuilderTest extends TestCase {
->setFormFields($formValues) ->setFormFields($formValues)
->getFullRequest(); ->getFullRequest();
$response = Amp\wait((new Client)->request($request)); $response = wait((new HummingbirdClient)->request($request));
$body = Json::decode($response->getBody()); $body = Json::decode(wait($response->getBody()));
$this->assertEquals($formValues, $body['form']); $this->assertEquals($formValues, $body['form']);
} }
@ -129,8 +128,8 @@ class APIRequestBuilderTest extends TestCase {
->setJsonBody($data) ->setJsonBody($data)
->getFullRequest(); ->getFullRequest();
$response = Amp\wait((new Client)->request($request)); $response = wait((new HummingbirdClient)->request($request));
$body = Json::decode($response->getBody()); $body = Json::decode(wait($response->getBody()));
$this->assertEquals($data, $body['json']); $this->assertEquals($data, $body['json']);
} }

View File

@ -46,6 +46,5 @@ class MALTraitTest extends AnimeClientTestCase {
]); ]);
$this->assertInstanceOf(\Amp\Artax\Request::class, $request); $this->assertInstanceOf(\Amp\Artax\Request::class, $request);
$this->assertEquals($request->getUri(), 'https://myanimelist.net/api/foo?foo=bar'); $this->assertEquals($request->getUri(), 'https://myanimelist.net/api/foo?foo=bar');
$this->assertEquals($request->getBody(), '');
} }
} }

View File

@ -53,9 +53,9 @@ class AnimeClientTestCase extends TestCase {
public static function setUpBeforeClass() public static function setUpBeforeClass()
{ {
// Use mock session handler // Use mock session handler
$session_handler = new TestSessionHandler(); //$session_handler = new TestSessionHandler();
session_set_save_handler($session_handler, TRUE); //session_set_save_handler($session_handler, TRUE);
self::$session_handler = $session_handler; //self::$session_handler = $session_handler;
// Remove test cache files // Remove test cache files
$files = glob(_dir(TEST_DATA_DIR, 'cache', '*.json')); $files = glob(_dir(TEST_DATA_DIR, 'cache', '*.json'));