diff --git a/app/base/BaseApiModel.php b/app/base/BaseApiModel.php index 6458fdb0..f8ddda9f 100644 --- a/app/base/BaseApiModel.php +++ b/app/base/BaseApiModel.php @@ -44,17 +44,5 @@ class BaseApiModel extends BaseModel { ] ]); } - - /** - * Get the full url path, since the base_url in Guzzle doesn't work correctly - * - * @param string $path - * @return string - */ - protected function _url($path) - { - return "{$this->base_url}{$path}"; - } - } // End of BaseApiModel.php \ No newline at end of file diff --git a/app/base/BaseController.php b/app/base/BaseController.php index 20a3e0a5..73c7d48b 100644 --- a/app/base/BaseController.php +++ b/app/base/BaseController.php @@ -97,5 +97,16 @@ class BaseController { header("Location: {$url}"); die(); } + + /** + * Clear the api session + * + * @return void + */ + public function logout() + { + session_destroy(); + $this->redirect(''); + } } // End of BaseController.php \ No newline at end of file diff --git a/app/base/Router.php b/app/base/Router.php index b7704c6b..f9179550 100644 --- a/app/base/Router.php +++ b/app/base/Router.php @@ -90,8 +90,7 @@ class Router { } else { - $controller_name = $route->params['controller']; - $action_method = $route->params['action']; + list($controller_name, $action_method) = $route->params['action']; $params = (isset($route->params['params'])) ? $route->params['params'] : []; if ( ! empty($route->tokens)) @@ -133,7 +132,7 @@ class Router { $routes = $this->config->routes; - // Add routes by the configuration file + // Add routes for the current controller foreach($routes[$route_type] as $name => $route) { $path = $route['path']; @@ -153,6 +152,21 @@ class Router { ->addTokens($tokens); } } + + // Add routes by required http verb + foreach(['get', 'post'] as $verb) + { + $add = "add" . ucfirst($verb); + + foreach($routes[$verb] as $name => $route) + { + $path = $route['path']; + unset($route['path']); + + $this->router->$add($name, $path) + ->addValues($route); + } + } } } // End of Router.php \ No newline at end of file diff --git a/app/config/routes.php b/app/config/routes.php index e164aa80..e2e201d5 100644 --- a/app/config/routes.php +++ b/app/config/routes.php @@ -4,8 +4,7 @@ return [ 'anime' => [ 'index' => [ 'path' => '/', - 'controller' => 'AnimeController', - 'action' => 'redirect', + 'action' => ['AnimeController', 'redirect'], 'params' => [ 'url' => '', // Determined by config 'code' => '301' @@ -13,8 +12,7 @@ return [ ], 'all' => [ 'path' => '/all{/view}', - 'controller' => 'AnimeController', - 'action' => 'anime_list', + 'action' => ['AnimeController', 'anime_list'], 'params' => [ 'type' => 'all', 'title' => WHOSE . " Anime List · All" @@ -25,8 +23,7 @@ return [ ], 'watching' => [ 'path' => '/watching{/view}', - 'controller' => 'AnimeController', - 'action' => 'anime_list', + 'action' => ['AnimeController', 'anime_list'], 'params' => [ 'type' => 'currently-watching', 'title' => WHOSE . " Anime List · Watching" @@ -37,8 +34,7 @@ return [ ], 'plan_to_watch' => [ 'path' => '/plan_to_watch{/view}', - 'controller' => 'AnimeController', - 'action' => 'anime_list', + 'action' => ['AnimeController', 'anime_list'], 'params' => [ 'type' => 'plan-to-watch', 'title' => WHOSE . " Anime List · Plan to Watch" @@ -49,8 +45,7 @@ return [ ], 'on_hold' => [ 'path' => '/on_hold{/view}', - 'controller' => 'AnimeController', - 'action' => 'anime_list', + 'action' => ['AnimeController', 'anime_list'], 'params' => [ 'type' => 'on-hold', 'title' => WHOSE . " Anime List · On Hold" @@ -61,8 +56,7 @@ return [ ], 'dropped' => [ 'path' => '/dropped{/view}', - 'controller' => 'AnimeController', - 'action' => 'anime_list', + 'action' => ['AnimeController', 'anime_list'], 'params' => [ 'type' => 'dropped', 'title' => WHOSE . " Anime List · Dropped" @@ -73,8 +67,7 @@ return [ ], 'completed' => [ 'path' => '/completed{/view}', - 'controller' => 'AnimeController', - 'action' => 'anime_list', + 'action' => ['AnimeController', 'anime_list'], 'params' => [ 'type' => 'completed', 'title' => WHOSE . " Anime List · Completed" @@ -85,8 +78,7 @@ return [ ], 'collection' => [ 'path' => '/collection{/view}', - 'controller' => 'AnimeController', - 'action' => 'collection', + 'action' => ['AnimeController', 'collection'], 'params' => [], 'tokens' => [ 'view' => '[a-z_]+' @@ -96,8 +88,7 @@ return [ 'manga' => [ 'index' => [ 'path' => '/', - 'controller' => 'MangaController', - 'action' => 'redirect', + 'action' => ['MangaController', 'redirect'], 'params' => [ 'url' => '', // Determined by config 'code' => '301', @@ -106,8 +97,7 @@ return [ ], 'all' => [ 'path' => '/all{/view}', - 'controller' => 'MangaController', - 'action' => 'manga_list', + 'action' => ['MangaController', 'manga_list'], 'params' => [ 'type' => 'all', 'title' => WHOSE . " Manga List · All" @@ -118,8 +108,7 @@ return [ ], 'reading' => [ 'path' => '/reading{/view}', - 'controller' => 'MangaController', - 'action' => 'manga_list', + 'action' => ['MangaController', 'manga_list'], 'params' => [ 'type' => 'Reading', 'title' => WHOSE . " Manga List · Reading" @@ -130,8 +119,7 @@ return [ ], 'plan_to_read' => [ 'path' => '/plan_to_read{/view}', - 'controller' => 'MangaController', - 'action' => 'manga_list', + 'action' => ['MangaController', 'manga_list'], 'params' => [ 'type' => 'Plan to Read', 'title' => WHOSE . " Manga List · Plan to Read" @@ -142,8 +130,7 @@ return [ ], 'on_hold' => [ 'path' => '/on_hold{/view}', - 'controller' => 'MangaController', - 'action' => 'manga_list', + 'action' => ['MangaController', 'manga_list'], 'params' => [ 'type' => 'On Hold', 'title' => WHOSE . " Manga List · On Hold" @@ -154,8 +141,7 @@ return [ ], 'dropped' => [ 'path' => '/dropped{/view}', - 'controller' => 'MangaController', - 'action' => 'manga_list', + 'action' => ['MangaController', 'manga_list'], 'params' => [ 'type' => 'Dropped', 'title' => WHOSE . " Manga List · Dropped" @@ -166,8 +152,7 @@ return [ ], 'completed' => [ 'path' => '/completed{/view}', - 'controller' => 'MangaController', - 'action' => 'manga_list', + 'action' => ['MangaController', 'manga_list'], 'params' => [ 'type' => 'Completed', 'title' => WHOSE . " Manga List · Completed" @@ -176,5 +161,22 @@ return [ 'view' => '[a-z_]+' ] ], + ], + // These routes are limited to a specific HTTP verb + 'get' => [ + 'login_form' => [ + 'path' => '/login', + 'action' => ['AnimeController', 'login'], + ], + 'logout' => [ + 'path' => '/logout', + 'action' => ['BaseController', 'logout'] + ] + ], + 'post' => [ + 'login_action' => [ + 'path' => '/login', + 'action' => ['AnimeController', 'login_action'], + ] ] ]; \ No newline at end of file diff --git a/app/controllers/AnimeController.php b/app/controllers/AnimeController.php index 75b1c7f8..bbd5505d 100644 --- a/app/controllers/AnimeController.php +++ b/app/controllers/AnimeController.php @@ -104,5 +104,30 @@ class AnimeController extends BaseController { 'sections' => $data ])); } + + /** + * Show the login form + * + * @return void + */ + public function login() + { + $this->outputHTML('login', array_merge($this->base_data, [ + 'title' => 'Api login' + ])); + } + + /** + * Attempt to log in with the api + * + * @return void + */ + public function login_action() + { + if ($this->model->authenticate($this->config->hummingbird_username, $_POST['password'])) + { + $this->redirect(''); + } + } } // End of AnimeController.php \ No newline at end of file diff --git a/app/models/AnimeModel.php b/app/models/AnimeModel.php index 8ae915c6..dc6499a7 100644 --- a/app/models/AnimeModel.php +++ b/app/models/AnimeModel.php @@ -11,7 +11,7 @@ class AnimeModel extends BaseApiModel { * The base url for api requests * @var string $base_url */ - protected $base_url = "https://hummingbird.me/api/v1"; + protected $base_url = "https://hummingbird.me/api/v1/"; /** * Constructor @@ -21,6 +21,31 @@ class AnimeModel extends BaseApiModel { parent::__construct(); } + /** + * Attempt login via the api + * + * @param string $username + * @param string $password + * @return bool + */ + public function authenticate($username, $password) + { + $result = $this->client->post('users/authenticate', [ + 'form_params' => [ + 'username' => $this->config->hummingbird_username, + 'password' => $password + ] + ]); + + if ($response->getStatusCode() === 201) + { + $_SESSION['hummingbird_anime_token'] = $response->json(); + return TRUE; + } + + return FALSE; + } + /** * Get the full set of anime lists * @@ -111,9 +136,9 @@ class AnimeModel extends BaseApiModel { $cache_file = "{$this->config->data_cache_path}/anime-{$status}.json"; $config = [ - 'query' => [ + /*'query' => [ 'username' => $this->config->hummingbird_username, - ], + ],*/ 'allow_redirects' => false ]; @@ -122,7 +147,7 @@ class AnimeModel extends BaseApiModel { $config['query']['status'] = $status; } - $response = $this->client->get($this->_url('/users/' . $this->config->hummingbird_username . '/library'), $config); + $response = $this->client->get("users/{$this->config->hummingbird_username}/library", $config); $defaultHandler->addDataTable('anime_list_response', (array)$response); @@ -171,7 +196,7 @@ class AnimeModel extends BaseApiModel { ] ]; - $response = $this->client->get($this->_url("/anime/{$anime_id}"), $config); + $response = $this->client->get("anime/{$anime_id}", $config); return $response->json(); } @@ -192,7 +217,7 @@ class AnimeModel extends BaseApiModel { ] ]; - $response = $this->client->get($this->_url('/search/anime'), $config); + $response = $this->client->get('search/anime', $config); $defaultHandler->addDataTable('anime_search_response', (array)$response); if ($response->getStatusCode() != 200) diff --git a/app/models/MangaModel.php b/app/models/MangaModel.php index b9df671c..9d00b629 100644 --- a/app/models/MangaModel.php +++ b/app/models/MangaModel.php @@ -11,7 +11,7 @@ class MangaModel extends BaseApiModel { /** * @var string $base_url - The base url for api requests */ - protected $base_url = "https://hummingbird.me"; + protected $base_url = "https://hummingbird.me/"; /** * Constructor @@ -72,7 +72,7 @@ class MangaModel extends BaseApiModel { 'allow_redirects' => false ]; - $response = $this->client->get($this->_url('/manga_library_entries'), $config); + $response = $this->client->get('manga_library_entries', $config); $defaultHandler->addDataTable('response', (array)$response); diff --git a/app/views/anime/collection.php b/app/views/anime/collection.php index 8faec9e6..28b40564 100644 --- a/app/views/anime/collection.php +++ b/app/views/anime/collection.php @@ -11,13 +11,14 @@ ({$item['alternate_title']})" : ""; ?> -
-
Episodes:
-
-
-
-
+
+
+
Episodes:
+
+
+
+ diff --git a/app/views/anime/collection_edit.php b/app/views/anime/collection_edit.php new file mode 100644 index 00000000..e69de29b diff --git a/app/views/anime/cover.php b/app/views/anime/cover.php index 480e6090..171fc0b6 100644 --- a/app/views/anime/cover.php +++ b/app/views/anime/cover.php @@ -6,19 +6,21 @@
- -
+ +
({$item['anime']['alternate_title']})" : ""; ?>
- -
diff --git a/app/views/login.php b/app/views/login.php index e69de29b..fe3f5f7f 100644 --- a/app/views/login.php +++ b/app/views/login.php @@ -0,0 +1,16 @@ +
+ +
\ No newline at end of file diff --git a/app/views/manga/cover.php b/app/views/manga/cover.php index 2c1465cc..c3294331 100644 --- a/app/views/manga/cover.php +++ b/app/views/manga/cover.php @@ -12,7 +12,7 @@ ({$item['manga']['english_title']})" : ""; ?>
-
0) ? (int)($item['rating'] * 2) : '-' ?> / 10
+
Rating: 0) ? (int)($item['rating'] * 2) : '-' ?> / 10
Chapters: / 0) ? $item['manga']['chapter_count'] : "-" ?> Volumes: / 0) ? $item['manga']['volume_count'] : "-" ?>*/ ?> diff --git a/public/css/base.css b/public/css/base.css index 0b50eeda..74c3fd5d 100644 --- a/public/css/base.css +++ b/public/css/base.css @@ -50,6 +50,8 @@ tbody > tr:nth-child(odd) { margin:0.25em; } + + .name, .media_type, .airing_status, .user_rating, .completion, .age_rating { text-shadow: 1px 2px 1px rgba(0, 0, 0, 0.85); background: rgba(0, 0, 0, 0.45); @@ -81,9 +83,10 @@ tbody > tr:nth-child(odd) { .media:hover > .name, .media:hover > .media_metadata > div, - .media:hover > .medium_metadata > div + .media:hover > .medium_metadata > div, + .media:hover > .table .row { - background:rgba(0,0,0,0.9); + background:rgba(0,0,0,0.75); } .media > .name > a { @@ -93,8 +96,42 @@ tbody > tr:nth-child(odd) { text-shadow: 1px 2px 1px rgba(0, 0, 0, 0.85); } -.user_rating::before { - content: "Rating: "; + +/* ----------------------------------------------------------------------------- + Anime-list-specific styles +------------------------------------------------------------------------------*/ +.anime .name {width:100%;} + +.anime .media_type, +.anime .airing_status, +.anime .user_rating, +.anime .completion, +.anime .age_rating { + background: none; + text-align:center; +} + + +.anime .table { + position:absolute; + bottom:0; + left:0; + width:100%; +} + +.anime .row { + width:100%; + background: rgba(0, 0, 0, 0.45); + display:table; + text-align:center; + padding:0 inherit; +} + +.anime .row > div { + font-size:0.8em; + display:table-cell; + text-align:center; + vertical-align:middle; } /* -----------------------------------------------------------------------------