Merge pull request #13 from timw4mail/develop

Sync with dev
This commit is contained in:
Timothy Warren 2016-01-11 15:44:57 -05:00
commit c59288b5f9
18 changed files with 3162 additions and 289 deletions

View File

@ -38,7 +38,7 @@ A self-hosted client that allows custom formatting of data from the hummingbird
### Installation
1. Install dependencies via composer: `composer install`
1. Install via composer: `composer create-project timw4mail/hummingbird-anime-client`
2. Configure settings in `app/config/config.php` to your liking
3. Create the following directories if they don't exist, and make sure they are world writable
* app/cache
@ -51,7 +51,7 @@ A self-hosted client that allows custom formatting of data from the hummingbird
* For importing anime:
1. Login
2. Use the form to select your media
3. Save & Repeat as needed
3. Save & Repeat as needed
* For bulk importing anime:
1. Find the anime you are looking for on the hummingbird search api page: `https://hummingbird.me/api/v1/search/anime?query=`
2. Create an `import.json` file in the root of the app, with an array of objects from the search page that you want to import

View File

@ -29,8 +29,7 @@ return function(array $config_array = []) {
$app_logger = new Logger('animeclient');
$app_logger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/app.log', Logger::NOTICE));
$app_logger->pushHandler(new BrowserConsoleHandler(Logger::DEBUG));
$container->setLogger($app_logger);
$container->setLogger($app_logger, 'default');
// -------------------------------------------------------------------------
// Injected Objects

205
build.xml
View File

@ -1,251 +1,158 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="animeclient" default="full-build">
<project default="full-build" name="animeclient" basedir=".">
<!-- By default, we assume all tools to be on the $PATH -->
<property name="pdepend" value="pdepend" />
<property name="phpcpd" value="phpcpd" />
<property name="phpcs" value="phpcs"/>
<property name="phpdox" value="phpdox" />
<property name="phploc" value="phploc" />
<property name="phpmd" value="phpmd" />
<property name="phpunit" value="phpunit" />
<property name="sonar" value="sonar-runner" />
<!-- Use this when the tools are located as PHARs in ${basedir}/build/tools
<property name="pdepend" value="${basedir}/build/tools/pdepend.phar"/>
<property name="phpcpd" value="${basedir}/build/tools/phpcpd.phar"/>
<property name="phpcs" value="${basedir}/build/tools/phpcs.phar"/>
<property name="phpdox" value="${basedir}/build/tools/phpdox.phar"/>
<property name="phploc" value="${basedir}/build/tools/phploc.phar"/>
<property name="phpmd" value="${basedir}/build/tools/phpmd.phar"/>
<property name="phpunit" value="${basedir}/build/tools/phpunit.phar"/> -->
<!-- Use this when the tools are managed by Composer in ${basedir}/vendor/bin
<property name="pdepend" value="${basedir}/vendor/bin/pdepend"/>
<property name="phpcpd" value="${basedir}/vendor/bin/phpcpd"/>
<property name="phpcs" value="${basedir}/vendor/bin/phpcs"/>
<property name="phpdox" value="${basedir}/vendor/bin/phpdox"/>
<property name="phploc" value="${basedir}/vendor/bin/phploc"/>
<property name="phpmd" value="${basedir}/vendor/bin/phpmd"/>
<property name="phpunit" value="${basedir}/vendor/bin/phpunit"/> -->
<target name="full-build"
depends="prepare,static-analysis,phpunit,phpdox,sonar,-check-failure"
description="Performs static analysis, runs the tests, and generates project documentation"/>
depends="prepare,static-analysis,phpunit,phpdox,sonar"
description="Performs static analysis, runs the tests, and generates project documentation"
/>
<target name="full-build-parallel"
depends="prepare,static-analysis-parallel,phpunit,phpdox,-check-failure"
description="Performs static analysis (executing the tools in parallel), runs the tests, and generates project documentation"/>
depends="prepare,static-analysis-parallel,phpunit,phpdox"
description="Performs static analysis (executing the tools in parallel), runs the tests, and generates project documentation"
/>
<target name="quick-build"
depends="prepare,lint,phpunit-no-coverage"
description="Performs a lint check and runs the tests (without generating code coverage reports)"/>
description="Performs a lint check and runs the tests (without generating code coverage reports)"
/>
<target name="static-analysis"
depends="lint,phploc-ci,pdepend,phpcs-ci,phpcpd-ci"
description="Performs static analysis" />
depends="lint,phploc-ci,pdepend,phpcpd-ci"
description="Performs static analysis"
/>
<!-- Adjust the threadCount attribute's value to the number of CPUs -->
<target name="static-analysis-parallel"
description="Performs static analysis (executing the tools in parallel)">
<parallel threadCount="2">
<target name="static-analysis-parallel" description="Performs static analysis (executing the tools in parallel)">
<parallel threadCount="6">
<sequential>
<antcall target="pdepend" />
</sequential>
<antcall target="lint" />
<antcall target="phpcpd-ci" />
<antcall target="phpcs-ci"/>
<antcall target="phploc-ci" />
</parallel>
</target>
<target name="clean"
unless="clean.done"
description="Cleanup build artifacts">
<delete dir="${basedir}/build/api"/>
<delete dir="${basedir}/build/coverage"/>
<delete dir="${basedir}/build/logs"/>
<delete dir="${basedir}/build/pdepend"/>
<delete dir="${basedir}/build/phpdox"/>
<target name="clean" unless="clean.done" description="Cleanup build artifacts">
<delete dir="build/api" />
<delete dir="build/coverage" />
<delete dir="build/logs" />
<delete dir="build/pdepend" />
<delete dir="build/phpdox" />
<property name="clean.done" value="true" />
</target>
<target name="prepare"
unless="prepare.done"
depends="clean"
description="Prepare for build">
<mkdir dir="${basedir}/build/api"/>
<mkdir dir="${basedir}/build/coverage"/>
<mkdir dir="${basedir}/build/logs"/>
<mkdir dir="${basedir}/build/pdepend"/>
<mkdir dir="${basedir}/build/phpdox"/>
<target name="prepare" depends="clean" unless="prepare.done" description="Prepare for build">
<mkdir dir="build/api" />
<mkdir dir="build/coverage" />
<mkdir dir="build/logs" />
<mkdir dir="build/pdepend" />
<mkdir dir="build/phpdox" />
<property name="prepare.done" value="true" />
</target>
<target name="lint"
unless="lint.done"
description="Perform syntax check of sourcecode files">
<target name="lint" unless="lint.done" description="Perform syntax check of sourcecode files">
<apply executable="php" taskname="lint">
<arg value="-l" />
<fileset dir="${basedir}/src">
<fileset dir="src">
<include name="**/*.php" />
<modified />
</fileset>
<fileset dir="${basedir}/tests">
<fileset dir="tests">
<include name="**/*.php" />
<modified />
</fileset>
</apply>
<property name="lint.done" value="true" />
</target>
<target name="phploc"
unless="phploc.done"
description="Measure project size using PHPLOC and print human readable output. Intended for usage on the command line.">
<target name="phploc" unless="phploc.done" description="Measure project size using PHPLOC and print human readable output. Intended for usage on the command line.">
<exec executable="${phploc}" taskname="phploc">
<arg value="--count-tests" />
<arg path="${basedir}/src" />
<arg path="${basedir}/tests" />
<arg path="src" />
<arg path="tests" />
</exec>
<property name="phploc.done" value="true" />
</target>
<target name="phploc-ci"
unless="phploc.done"
depends="prepare"
description="Measure project size using PHPLOC and log result in CSV and XML format. Intended for usage within a continuous integration environment.">
<target name="phploc-ci" depends="prepare" unless="phploc.done" description="Measure project size using PHPLOC and log result in CSV and XML format. Intended for usage within a continuous integration environment.">
<exec executable="${phploc}" taskname="phploc">
<arg value="--count-tests" />
<arg value="--log-csv" />
<arg path="${basedir}/build/logs/phploc.csv" />
<arg path="build/logs/phploc.csv" />
<arg value="--log-xml" />
<arg path="${basedir}/build/logs/phploc.xml" />
<arg path="${basedir}/src" />
<arg path="${basedir}/tests" />
<arg path="build/logs/phploc.xml" />
<arg path="src" />
<arg path="tests" />
</exec>
<property name="phploc.done" value="true" />
</target>
<target name="pdepend"
unless="pdepend.done"
depends="prepare"
description="Calculate software metrics using PHP_Depend and log result in XML format. Intended for usage within a continuous integration environment.">
<target name="pdepend" depends="prepare" unless="pdepend.done" description="Calculate software metrics using PHP_Depend and log result in XML format. Intended for usage within a continuous integration environment.">
<exec executable="${pdepend}" taskname="pdepend">
<arg value="--jdepend-xml=${basedir}/build/logs/jdepend.xml" />
<arg value="--jdepend-chart=${basedir}/build/pdepend/dependencies.svg" />
<arg value="--overview-pyramid=${basedir}/build/pdepend/overview-pyramid.svg" />
<arg path="${basedir}/src" />
<arg value="--jdepend-xml=build/logs/jdepend.xml" />
<arg value="--jdepend-chart=build/pdepend/dependencies.svg" />
<arg value="--overview-pyramid=build/pdepend/overview-pyramid.svg" />
<arg path="src" />
</exec>
<property name="pdepend.done" value="true" />
</target>
<target name="phpcs"
unless="phpcs.done"
description="Find coding standard violations using PHP_CodeSniffer and print human readable output. Intended for usage on the command line before committing.">
<exec executable="${phpcs}" taskname="phpcs">
<arg value="--standard=PSR2" />
<arg value="--extensions=php" />
<arg value="--ignore=autoload.php" />
<arg path="${basedir}/src" />
<arg path="${basedir}/tests" />
</exec>
<property name="phpcs.done" value="true"/>
</target>
<target name="phpcs-ci"
unless="phpcs.done"
depends="prepare"
description="Find coding standard violations using PHP_CodeSniffer and log result in XML format. Intended for usage within a continuous integration environment.">
<exec executable="${phpcs}" output="/dev/null" taskname="phpcs">
<arg value="--report=checkstyle" />
<arg value="--report-file=${basedir}/build/logs/checkstyle.xml" />
<arg value="--standard=PSR2" />
<arg value="--extensions=php" />
<arg value="--ignore=autoload.php" />
<arg path="${basedir}/src" />
<arg path="${basedir}/tests" />
</exec>
<property name="phpcs.done" value="true"/>
</target>
<target name="phpcpd"
unless="phpcpd.done"
description="Find duplicate code using PHPCPD and print human readable output. Intended for usage on the command line before committing.">
<target name="phpcpd" unless="phpcpd.done" description="Find duplicate code using PHPCPD and print human readable output. Intended for usage on the command line before committing.">
<exec executable="${phpcpd}" taskname="phpcpd">
<arg path="${basedir}/src" />
<arg path="src" />
</exec>
<property name="phpcpd.done" value="true" />
</target>
<target name="phpcpd-ci"
unless="phpcpd.done"
depends="prepare"
description="Find duplicate code using PHPCPD and log result in XML format. Intended for usage within a continuous integration environment.">
<target name="phpcpd-ci" depends="prepare" unless="phpcpd.done" description="Find duplicate code using PHPCPD and log result in XML format. Intended for usage within a continuous integration environment.">
<exec executable="${phpcpd}" taskname="phpcpd">
<arg value="--log-pmd" />
<arg path="${basedir}/build/logs/pmd-cpd.xml" />
<arg path="${basedir}/src" />
<arg path="build/logs/pmd-cpd.xml" />
<arg path="src" />
</exec>
<property name="phpcpd.done" value="true" />
</target>
<target name="phpunit"
unless="phpunit.done"
depends="prepare"
description="Run unit tests with PHPUnit">
<exec executable="${phpunit}" resultproperty="result.phpunit" taskname="phpunit">
<target name="phpunit" unless="phpunit.done" depends="prepare" description="Run unit tests with PHPUnit">
<exec executable="${phpunit}" taskname="phpunit">
<arg value="--configuration" />
<arg path="${basedir}/build/phpunit.xml"/>
<arg path="build/phpunit.xml" />
</exec>
<property name="phpunit.done" value="true" />
</target>
<target name="phpunit-no-coverage"
unless="phpunit.done"
depends="prepare"
description="Run unit tests with PHPUnit (without generating code coverage reports)">
<target name="phpunit-no-coverage" depends="prepare" unless="phpunit.done" description="Run unit tests with PHPUnit (without generating code coverage reports)">
<exec executable="${phpunit}" failonerror="true" taskname="phpunit">
<arg value="--configuration" />
<arg path="${basedir}/build/phpunit.xml"/>
<arg path="build/phpunit.xml" />
<arg value="--no-coverage" />
</exec>
<property name="phpunit.done" value="true" />
</target>
<target name="phpdox"
unless="phpdox.done"
depends="phploc-ci,phpcs-ci,phpunit"
description="Generate project documentation using phpDox">
<exec executable="${phpdox}" dir="${basedir}/build" taskname="phpdox"/>
<target name="phpdox" depends="phploc-ci,phpunit" unless="phpdox.done" description="Generate project documentation using phpDox">
<exec dir="build" executable="${phpdox}" taskname="phpdox" />
<property name="phpdox.done" value="true" />
</target>
<target name="sonar"
depends="phpunit">
<target name="sonar" depends="phpunit" unless="sonar.done" description="Generate code analysis with sonarqube">
<exec executable="${sonar}" taskname="sonar" />
<property name="sonar.done" value="true" />
</target>
<target name="-check-failure">
<fail message="PHPUnit did not finish successfully">
<condition>
<not>
<equals arg1="${result.phpunit}" arg2="0"/>
</not>
</condition>
</fail>
</target>
</project>

View File

@ -7,16 +7,15 @@
"aura/html": "2.*",
"aura/router": "2.2.*",
"aura/session": "2.*",
"aura/web": "2.0.*",
"aura/web": "2.*",
"aviat4ion/query": "2.5.*",
"container-interop/container-interop": "1.*",
"danielstjules/stringy": "~2.1",
"filp/whoops": "1.1.*",
"filp/whoops": "2.0.*",
"guzzlehttp/guzzle": "6.*",
"monolog/monolog": "1.*",
"mustache/mustache": "*",
"psr/log": "~1.0",
"robmorgan/phinx": "0.4.*",
"szymach/c-pchart": "1.*"
"yosymfony/toml": "0.3.*"
}
}

View File

@ -66,7 +66,6 @@ $whoops->pushHandler($defaultHandler);
// Set up json handler for ajax errors
$jsonHandler = new JsonResponseHandler();
$jsonHandler->onlyForAjaxRequests(TRUE);
$whoops->pushHandler($jsonHandler);
// Register as the error handler
@ -86,7 +85,6 @@ unset($SRC_DIR);
unset($CONF_DIR);
$container = $di($config_array);
$container->set('error-handler', $defaultHandler);
// -----------------------------------------------------------------------------
// Dispatch to the current route

View File

@ -197,8 +197,6 @@ class Controller {
*/
protected function load_partial($view, $template, array $data = [])
{
$errorHandler = $this->container->get('error-handler');
$errorHandler->addDataTable('Template Data', $data);
$router = $this->container->get('dispatcher');
if (isset($this->base_data))

View File

@ -110,11 +110,13 @@ class Collection extends BaseController {
*/
public function form($id = NULL)
{
$this->set_session_redirect();
$action = (is_null($id)) ? "Add" : "Edit";
$this->outputHTML('collection/' . strtolower($action), [
'action' => $action,
'action_url' => $this->urlGenerator->full_url("collection/" . strtolower($action)),
'action_url' => $this->urlGenerator->full_url('collection/' . strtolower($action)),
'title' => $this->config->get('whose_list') . " Anime Collection &middot; {$action}",
'media_items' => $this->anime_collection_model->get_media_type_list(),
'item' => ($action === "Edit") ? $this->anime_collection_model->get($id) : []
@ -129,14 +131,17 @@ class Collection extends BaseController {
public function edit()
{
$data = $this->request->post->get();
if ( ! array_key_exists('hummingbird_id', $data))
if (array_key_exists('hummingbird_id', $data))
{
$this->redirect("collection/view", 303);
$this->anime_collection_model->update($data);
$this->set_flash_message('Successfully updated collection item.', 'success');
}
else
{
$this->set_flash_message('Failed to update collection item', 'error');
}
$this->anime_collection_model->update($data);
$this->redirect("collection/view", 303);
$this->session_redirect();
}
/**
@ -147,14 +152,17 @@ class Collection extends BaseController {
public function add()
{
$data = $this->request->post->get();
if ( ! array_key_exists('id', $data))
if (array_key_exists('id', $data))
{
$this->redirect("collection/view", 303);
$this->anime_collection_model->add($data);
$this->set_flash_message('Successfully added collection item', 'success');
}
else
{
$this->set_flash_message('Failed to add collection item.', 'error');
}
$this->anime_collection_model->add($data);
$this->redirect("collection/view", 303);
$this->session_redirect();
}
/**

View File

@ -62,14 +62,15 @@ class Dispatcher extends RoutingBase {
*/
public function get_route()
{
$error_handler = $this->container->get('error-handler');
$logger = $this->container->getLogger('default');
$raw_route = $this->request->url->get(PHP_URL_PATH);
$route_path = "/" . trim($raw_route, '/');
$error_handler->addDataTable('Route Info', [
$logger->debug('Dispatcher - Routing data from get_route method');
$logger->debug(print_r([
'route_path' => $route_path
]);
], TRUE));
return $this->router->match($route_path, $_SERVER);
}
@ -93,12 +94,14 @@ class Dispatcher extends RoutingBase {
*/
public function __invoke($route = NULL)
{
$error_handler = $this->container->get('error-handler');
$logger = $this->container->getLogger('default');
if (is_null($route))
{
$route = $this->get_route();
$error_handler->addDataTable('route_args', (array)$route);
$logger->debug('Dispatcher - Route invoke arguments');
$logger->debug(print_r($route, TRUE));
}
if($route)
@ -233,12 +236,13 @@ class Dispatcher extends RoutingBase {
*/
protected function call($controller_name, $method, array $params)
{
$error_handler = $this->container->get('error-handler');
$logger = $this->container->getLogger('default');
$controller = new $controller_name($this->container);
// Run the appropriate controller method
$error_handler->addDataTable('controller_args', $params);
$logger->debug('Dispatcher - controller arguments');
$logger->debug(print_r($params, TRUE));
call_user_func_array([$controller, $method], $params);
}
@ -250,9 +254,12 @@ class Dispatcher extends RoutingBase {
*/
protected function get_error_params()
{
$logger = $this->container->getLogger('default');
$failure = $this->router->getFailedRoute();
$error_handler = $this->container->get('error-handler');
$error_handler->addDataTable('failed_route', (array)$failure);
$logger->info('Dispatcher - failed route');
$logger->info(print_r($failure, TRUE));
$action_method = AnimeClient::ERROR_MESSAGE_METHOD;
$params = [];

View File

@ -149,7 +149,7 @@ class Anime extends API {
*/
public function search($name)
{
$errorHandler = $this->container->get('error-handler');
$logger = $this->container->getLogger('default');
$config = [
'query' => [
@ -158,10 +158,12 @@ class Anime extends API {
];
$response = $this->get('search/anime', $config);
$errorHandler->addDataTable('anime_search_response', (array)$response);
if ($response->getStatusCode() != 200)
{
$logger->warning("Non 200 response for search api call");
$logger->warning($response->getBody());
throw new RuntimeException($response->getEffectiveUrl());
}

View File

@ -60,6 +60,7 @@ class HttpView extends BaseView {
/**
* Send the appropriate response
*
* @codeCoverageIgnore
* @return void
*/
protected function output()

View File

@ -1,11 +1,15 @@
<?php
use Aura\Web\WebFactory;
use Aura\Router\RouterFactory;
use Monolog\Logger;
use Monolog\Handler\TestHandler;
use Aviat\Ion\Di\Container;
use Aviat\AnimeClient\Dispatcher;
use Aviat\AnimeClient\Config;
use Aviat\AnimeClient\UrlGenerator;
use Aura\Web\WebFactory;
use Aura\Router\RouterFactory;
class DispatcherTest extends AnimeClient_TestCase {
@ -35,15 +39,19 @@ class DispatcherTest extends AnimeClient_TestCase {
$old_config = $this->container->get('config');
$logger = new Logger('test_logger');
$logger->pushHandler(new TestHandler(Logger::DEBUG));
// Add the appropriate objects to the container
$this->container = new Container([
'config' => $old_config,
'request' => $web_factory->newRequest(),
'response' => $web_factory->newResponse(),
'aura-router' => $router_factory->newInstance(),
'error-handler' => new MockErrorHandler()
'aura-router' => $router_factory->newInstance()
]);
$this->container->setLogger($logger, 'default');
if ( ! empty($config))
{
$config = new Config($config);

View File

@ -57,43 +57,35 @@ class MangaModelTest extends AnimeClient_TestCase {
public function testGetList()
{
$this->markTestSkipped();
if (($var = getenv('CI')))
{
$this->markTestSkipped();
}
$data = $this->model->get_all_lists();
$this->assertEquals($data['Reading'], $this->model->get_list('Reading'));
$data = file_get_contents($this->mockDir . '/manga.json');
$client = $this->getMockClient(200, [
'Content-type' => 'application/json'
], $data);
$this->model->__set('client', $client);
$expected = Json::decodeFile($this->mockDir . '/get-all-lists.json');
$this->assertEquals($expected['Reading'], $this->model->get_list('Reading'));
}
public function testGetAllLists()
{
$this->markTestSkipped();
if (($var = getenv('CI')))
{
$this->markTestSkipped();
}
$data = Json::decodeFile($this->mockDir . '/manga-mapped.json');
$data = file_get_contents($this->mockDir . '/manga.json');
$client = $this->getMockClient(200, [
'Content-type' => 'application/json'
], $data);
$this->model->__set('client', $client);
foreach($data as &$val)
{
$this->sort_by_name($val);
}
$this->assertEquals($data, $this->model->get_all_lists());
}
private function sort_by_name(&$array)
{
$sort = array();
foreach ($array as $key => $item)
{
$sort[$key] = $item['manga']['title'];
}
array_multisort($sort, SORT_ASC, $array);
$expected = Json::decodeFile($this->mockDir . '/get-all-lists.json');
$this->assertEquals($expected, $this->model->get_all_lists());
}
}

View File

@ -75,7 +75,6 @@ class AnimeClient_TestCase extends PHPUnit_Framework_TestCase {
// Set up DI container
$di = require _dir($APP_DIR, 'bootstrap.php');
$container = $di($config_array);
$container->set('error-handler', new MockErrorHandler());
$container->set('session-handler', self::$session_handler);
$this->container = $container;

View File

@ -51,4 +51,10 @@ class HttpViewTest extends AnimeClient_TestCase {
$this->assertEquals($content->getCharset(), 'utf-8');
$this->assertEquals($content->get(), $this->friend->getOutput());
}
public function testSetStatusCode()
{
$this->view->setStatusCode(404);
$this->assertEquals(404, $this->friend->response->status->getCode());
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long