You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Application-Web/public/api/index.php

148 lines
4.3 KiB

<?php
require "../../config.php";
require "../../vendor/autoload.php";
require "../../sql/database.php";
require "../utils.php";
use App\Connexion;
use App\Controller\Api\APIAuthController;
use App\Controller\Api\APITacticController;
use App\Data\Account;
use App\Gateway\AccountGateway;
use App\Gateway\TacticInfoGateway;
use App\Http\HttpResponse;
use App\Http\JsonHttpResponse;
use App\Http\ViewHttpResponse;
use App\Model\AuthModel;
use App\Model\TacticModel;
use App\Session\PhpSessionHandle;
use App\Validation\ValidationFail;
function getTacticController(): APITacticController {
return new APITacticController(new TacticModel(new TacticInfoGateway(new Connexion(get_database()))));
}
function getAuthController(): APIAuthController {
return new APIAuthController(new AuthModel(new AccountGateway(new Connexion(get_database()))));
}
/**
* A Front controller action
*/
class Action {
/**
* @var callable(mixed[]): HttpResponse $action action to call
*/
private $action;
private bool $isAuthRequired;
/**
* @param callable(mixed[]): HttpResponse $action
*/
private function __construct(callable $action, bool $isAuthRequired) {
$this->action = $action;
$this->isAuthRequired = $isAuthRequired;
}
public function isAuthRequired(): bool {
return $this->isAuthRequired;
}
/**
* @param mixed[] $params
* @param ?Account $account
* @return HttpResponse
*/
public function run(array $params, ?Account $account): HttpResponse {
$params = array_values($params);
if ($this->isAuthRequired) {
if ($account == null) {
throw new Exception("action requires authorization.");
}
$params[] = $account;
}
return call_user_func_array($this->action, $params);
}
/**
* @param callable(mixed[]): HttpResponse $action
* @return Action an action that does not require to have an authorization.
*/
public static function noAuth(callable $action): Action {
return new Action($action, false);
}
/**
* @param callable(mixed[]): HttpResponse $action
* @return Action an action that does require to have an authorization.
*/
public static function auth(callable $action): Action {
return new Action($action, true);
}
}
/**
* @param mixed[] $match
* @return HttpResponse
* @throws Exception
*/
function handleMatch(array $match): HttpResponse {
if (!$match) {
return new JsonHttpResponse([ValidationFail::notFound("not found")]);
}
$action = $match['target'];
if (!$action instanceof Action) {
throw new Exception("routed action is not an Action object.");
}
$auth = null;
if ($action->isAuthRequired()) {
$auth = tryGetAuthAccount();
if ($auth == null) {
return new JsonHttpResponse([ValidationFail::unauthorized("Missing or invalid 'Authorization' header")]);
}
}
return $action->run($match['params'], $auth);
}
function tryGetAuthAccount(): ?Account {
$headers = getallheaders();
// If no authorization header is set, try fallback to php session.
if (!isset($headers['Authorization'])) {
$session = PhpSessionHandle::init();
return $session->getAccount();
}
$token = $headers['Authorization'];
$gateway = new AccountGateway(new Connexion(get_database()));
return $gateway->getAccountFromToken($token);
}
$router = new AltoRouter();
$router->setBasePath(get_public_path() . "/api");
$router->map("POST", "/tactic/[i:id]/edit/name", Action::auth(fn(int $id, Account $acc) => getTacticController()->updateName($id, $acc)));
$router->map("GET", "/tactic/[i:id]", Action::auth(fn(int $id, Account $acc) => getTacticController()->getTacticInfo($id, $acc)));
$router->map("POST", "/tactic/new", Action::auth(fn(Account $acc) => getTacticController()->newTactic($acc)));
$router->map("POST", "/auth", Action::noAuth(fn() => getAuthController()->authorize()));
$match = $router->match();
$response = handleMatch($match);
http_response_code($response->getCode());
if ($response instanceof JsonHttpResponse) {
header('Content-type: application/json');
echo $response->getJson();
} elseif ($response instanceof ViewHttpResponse) {
throw new Exception("API returned a view http response.");
}