diff --git a/Core/API/ApiKeyAPI.class.php b/Core/API/ApiKeyAPI.class.php
index c87f98b..0dcde96 100644
--- a/Core/API/ApiKeyAPI.class.php
+++ b/Core/API/ApiKeyAPI.class.php
@@ -9,6 +9,7 @@ namespace Core\API {
public function __construct(Context $context, bool $externalCall = false, array $params = array()) {
parent::__construct($context, $externalCall, $params);
+ $this->loginRequired = true;
}
protected function fetchAPIKey(int $apiKeyId): ApiKey|bool {
@@ -41,7 +42,6 @@ namespace Core\API\ApiKey {
public function __construct(Context $context, $externalCall = false) {
parent::__construct($context, $externalCall, array());
$this->apiKeyAllowed = false;
- $this->loginRequired = true;
}
public function _execute(): bool {
@@ -73,9 +73,7 @@ namespace Core\API\ApiKey {
public function __construct(Context $context, $externalCall = false) {
$params = $this->getPaginationParameters(["token", "validUntil", "active"]);
$params["showActiveOnly"] = new Parameter("showActiveOnly", Parameter::TYPE_BOOLEAN, true, true);
-
parent::__construct($context, $externalCall, $params);
- $this->loginRequired = true;
}
public function _execute(): bool {
@@ -119,7 +117,7 @@ namespace Core\API\ApiKey {
parent::__construct($context, $externalCall, array(
"id" => new Parameter("id", Parameter::TYPE_INT),
));
- $this->loginRequired = true;
+ $this->apiKeyAllowed = false;
}
public function _execute(): bool {
@@ -147,7 +145,6 @@ namespace Core\API\ApiKey {
parent::__construct($user, $externalCall, array(
"id" => new Parameter("id", Parameter::TYPE_INT),
));
- $this->loginRequired = true;
}
public function _execute(): bool {
diff --git a/Core/API/RoutesAPI.class.php b/Core/API/RoutesAPI.class.php
index 8f6cb60..94282fa 100644
--- a/Core/API/RoutesAPI.class.php
+++ b/Core/API/RoutesAPI.class.php
@@ -76,6 +76,7 @@ namespace Core\API\Routes {
use Core\Objects\DatabaseEntity\Route;
use Core\Objects\Router\ApiRoute;
use Core\Objects\Router\Router;
+ use Core\Objects\Router\StaticRoute;
class Fetch extends RoutesAPI {
@@ -102,108 +103,40 @@ namespace Core\API\Routes {
}
}
- class Save extends RoutesAPI {
-
- private array $routes;
+ class Get extends RoutesAPI {
public function __construct(Context $context, $externalCall = false) {
- parent::__construct($context, $externalCall, array(
- 'routes' => new Parameter('routes', Parameter::TYPE_ARRAY, false)
- ));
+ parent::__construct($context, $externalCall, [
+ "id" => new Parameter("id", Parameter::TYPE_INT)
+ ]);
}
public function _execute(): bool {
- if (!$this->validateRoutes()) {
- return false;
- }
-
$sql = $this->context->getSQL();
- $sql->startTransaction();
+ $routeId = $this->getParam("id");
- // DELETE old rules;
- $this->success = ($sql->truncate("Route")->execute() !== FALSE);
+ $route = Route::find($sql, $routeId);
$this->lastError = $sql->getLastError();
-
- // INSERT new routes
- if ($this->success) {
- $insertStatement = Route::getHandler($sql)->getInsertQuery($this->routes);
- $this->success = ($insertStatement->execute() !== FALSE);
- $this->lastError = $sql->getLastError();
- }
+ $this->success = ($route !== FALSE);
if ($this->success) {
- $sql->commit();
- return $this->regenerateCache();
- } else {
- $sql->rollback();
- return false;
- }
- }
-
- private function validateRoutes(): bool {
-
- $this->routes = array();
- $keys = array(
- "id" => Parameter::TYPE_INT,
- "pattern" => [Parameter::TYPE_STRING, Parameter::TYPE_INT],
- "type" => Parameter::TYPE_STRING,
- "target" => Parameter::TYPE_STRING,
- "extra" => Parameter::TYPE_STRING,
- "active" => Parameter::TYPE_BOOLEAN,
- "exact" => Parameter::TYPE_BOOLEAN,
- );
-
- foreach ($this->getParam("routes") as $index => $route) {
- foreach ($keys as $key => $expectedType) {
- if (!array_key_exists($key, $route)) {
- if ($key !== "id") { // id is optional
- return $this->createError("Route $index missing key: $key");
- } else {
- continue;
- }
- }
-
- $value = $route[$key];
- $type = Parameter::parseType($value);
- if (!is_array($expectedType)) {
- $expectedType = [$expectedType];
- }
-
- if (!in_array($type, $expectedType)) {
- if (count($expectedType) > 0) {
- $expectedTypeName = "expected: " . Parameter::names[$expectedType];
- } else {
- $expectedTypeName = "expected one of: " . implode(",", array_map(
- function ($type) {
- return Parameter::names[$type];
- }, $expectedType));
- }
- $gotTypeName = Parameter::names[$type];
- return $this->createError("Route $index has invalid value for key: $key, $expectedTypeName, got: $gotTypeName");
- }
+ if ($route === null) {
+ return $this->createError("Route not found");
+ } else {
+ $this->result["route"] = $route;
}
-
- $type = $route["type"];
- if (!isset(Route::ROUTE_TYPES[$type])) {
- return $this->createError("Invalid type: $type");
- }
-
- if (empty($route["pattern"])) {
- return $this->createError("Pattern cannot be empty.");
- }
-
- if (empty($route["target"])) {
- return $this->createError("Target cannot be empty.");
- }
-
- $this->routes[] = $route;
}
- return true;
+ return $this->success;
}
public static function getDefaultACL(Insert $insert): void {
- $insert->addRow(self::getEndpoint(), [Group::ADMIN], "Allows users to save the site routing", true);
+ $insert->addRow(
+ self::getEndpoint(),
+ [Group::ADMIN, Group::MODERATOR],
+ "Allows users to fetch a single route",
+ true
+ );
}
}
@@ -218,7 +151,6 @@ namespace Core\API\Routes {
"exact" => new Parameter("exact", Parameter::TYPE_BOOLEAN),
"active" => new Parameter("active", Parameter::TYPE_BOOLEAN, true, true),
));
- $this->isPublic = false;
}
public function _execute(): bool {
@@ -237,6 +169,11 @@ namespace Core\API\Routes {
$sql = $this->context->getSQL();
$this->success = $route->save($sql) !== false;
$this->lastError = $sql->getLastError();
+
+ if ($this->success) {
+ $this->result["routeId"] = $route->getId();
+ }
+
return $this->success && $this->regenerateCache();
}
@@ -256,7 +193,6 @@ namespace Core\API\Routes {
"exact" => new Parameter("exact", Parameter::TYPE_BOOLEAN),
"active" => new Parameter("active", Parameter::TYPE_BOOLEAN, true, true),
));
- $this->isPublic = false;
}
public function _execute(): bool {
@@ -417,24 +353,17 @@ namespace Core\API\Routes {
class Check extends RoutesAPI {
public function __construct(Context $context, bool $externalCall) {
parent::__construct($context, $externalCall, [
- "id" => new Parameter("id", Parameter::TYPE_INT),
- "path" => new StringType("path")
+ "pattern" => new StringType("pattern", 128),
+ "path" => new StringType("path"),
+ "exact" => new Parameter("exact", Parameter::TYPE_BOOLEAN, true, true)
]);
}
protected function _execute(): bool {
- $sql = $this->context->getSQL();
- $routeId = $this->getParam("id");
- $route = Route::find($sql, $routeId);
- if ($route === false) {
- $this->lastError = $sql->getLastError();
- return false;
- } else if ($route === null) {
- return $this->createError("Route not found");
- }
-
- $this->success = true;
$path = $this->getParam("path");
+ $pattern = $this->getParam("pattern");
+ $exact = $this->getParam("exact");
+ $route = new StaticRoute($pattern, $exact, "");
$this->result["match"] = $route->match($path);
return $this->success;
}
@@ -442,7 +371,7 @@ namespace Core\API\Routes {
public static function getDefaultACL(Insert $insert): void {
$insert->addRow("routes/check",
[Group::ADMIN, Group::MODERATOR],
- "Users with this permission can see, if a route is matched with the given path for debugging purposes",
+ "Users with this permission can see, if a route pattern is matched with the given path for debugging purposes",
true
);
}
diff --git a/Core/Objects/DatabaseEntity/Route.class.php b/Core/Objects/DatabaseEntity/Route.class.php
index 45cb640..634f767 100644
--- a/Core/Objects/DatabaseEntity/Route.class.php
+++ b/Core/Objects/DatabaseEntity/Route.class.php
@@ -10,7 +10,8 @@ use Core\Objects\DatabaseEntity\Attribute\MaxLength;
use Core\Objects\DatabaseEntity\Attribute\Unique;
use Core\Objects\DatabaseEntity\Controller\DatabaseEntity;
use Core\Objects\Router\DocumentRoute;
-use Core\Objects\Router\RedirectRoute;
+use Core\Objects\Router\RedirectPermanentlyRoute;
+use Core\Objects\Router\RedirectTemporaryRoute;
use Core\Objects\Router\Router;
use Core\Objects\Router\StaticFileRoute;
@@ -23,8 +24,8 @@ abstract class Route extends DatabaseEntity {
const TYPE_REDIRECT_PERMANENTLY = "redirect_permanently";
const TYPE_REDIRECT_TEMPORARY = "redirect_temporary";
const ROUTE_TYPES = [
- self::TYPE_REDIRECT_TEMPORARY => RedirectRoute::class,
- self::TYPE_REDIRECT_PERMANENTLY => RedirectRoute::class,
+ self::TYPE_REDIRECT_TEMPORARY => RedirectTemporaryRoute::class,
+ self::TYPE_REDIRECT_PERMANENTLY => RedirectPermanentlyRoute::class,
self::TYPE_STATIC => StaticFileRoute::class,
self::TYPE_DYNAMIC => DocumentRoute::class
];
@@ -60,6 +61,10 @@ abstract class Route extends DatabaseEntity {
return $this->active;
}
+ public function isExact(): bool {
+ return $this->exact;
+ }
+
private static function parseParamType(?string $type): ?int {
if ($type === null || trim($type) === "") {
return null;
diff --git a/Core/Objects/Router/RedirectPermanentlyRoute.class.php b/Core/Objects/Router/RedirectPermanentlyRoute.class.php
index f8cafe1..f30555f 100644
--- a/Core/Objects/Router/RedirectPermanentlyRoute.class.php
+++ b/Core/Objects/Router/RedirectPermanentlyRoute.class.php
@@ -2,8 +2,18 @@
namespace Core\Objects\Router;
+use Core\Driver\SQL\SQL;
+
class RedirectPermanentlyRoute extends RedirectRoute {
+
+ const HTTP_STATUS_CODE = 308;
+
public function __construct(string $pattern, bool $exact, string $destination) {
- parent::__construct("redirect_permanently", $pattern, $exact, $destination, 308);
+ parent::__construct("redirect_permanently", $pattern, $exact, $destination, self::HTTP_STATUS_CODE);
+ }
+
+ public function postFetch(SQL $sql, array $row) {
+ parent::postFetch($sql, $row);
+ $this->code = self::HTTP_STATUS_CODE;
}
}
\ No newline at end of file
diff --git a/Core/Objects/Router/RedirectRoute.class.php b/Core/Objects/Router/RedirectRoute.class.php
index 1c0ea39..60d6ebd 100644
--- a/Core/Objects/Router/RedirectRoute.class.php
+++ b/Core/Objects/Router/RedirectRoute.class.php
@@ -9,7 +9,7 @@ use JetBrains\PhpStorm\Pure;
class RedirectRoute extends Route {
#[Transient]
- private int $code;
+ protected int $code;
public function __construct(string $type, string $pattern, bool $exact, string $destination, int $code = 307) {
parent::__construct($type, $pattern, $destination, $exact);
diff --git a/Core/Objects/Router/RedirectTemporaryRoute.class.php b/Core/Objects/Router/RedirectTemporaryRoute.class.php
index e77745a..a9c15ac 100644
--- a/Core/Objects/Router/RedirectTemporaryRoute.class.php
+++ b/Core/Objects/Router/RedirectTemporaryRoute.class.php
@@ -2,8 +2,18 @@
namespace Core\Objects\Router;
+use Core\Driver\SQL\SQL;
+
class RedirectTemporaryRoute extends RedirectRoute {
+
+ const HTTP_STATUS_CODE = 307;
+
public function __construct(string $pattern, bool $exact, string $destination) {
- parent::__construct("redirect_temporary", $pattern, $exact, $destination, 307);
+ parent::__construct("redirect_temporary", $pattern, $exact, $destination, self::HTTP_STATUS_CODE);
+ }
+
+ public function postFetch(SQL $sql, array $row) {
+ parent::postFetch($sql, $row);
+ $this->code = self::HTTP_STATUS_CODE;
}
}
\ No newline at end of file
diff --git a/Core/Objects/Router/StaticRoute.class.php b/Core/Objects/Router/StaticRoute.class.php
index 553700f..81104bb 100644
--- a/Core/Objects/Router/StaticRoute.class.php
+++ b/Core/Objects/Router/StaticRoute.class.php
@@ -14,7 +14,7 @@ class StaticRoute extends Route {
private int $code;
public function __construct(string $pattern, bool $exact, string $data, int $code = 200) {
- parent::__construct("static", $pattern, $exact);
+ parent::__construct("static", $pattern, "", $exact);
$this->data = $data;
$this->code = $code;
}
diff --git a/react/admin-panel/src/AdminDashboard.jsx b/react/admin-panel/src/AdminDashboard.jsx
index 1e0e14b..b964fe3 100644
--- a/react/admin-panel/src/AdminDashboard.jsx
+++ b/react/admin-panel/src/AdminDashboard.jsx
@@ -20,7 +20,8 @@ const GroupListView = lazy(() => import('./views/group/group-list'));
const EditGroupView = lazy(() => import('./views/group/group-edit'));
const LogView = lazy(() => import("./views/log-view"));
const AccessControlList = lazy(() => import("./views/access-control-list"));
-const RouteListView = lazy(() => import("./views/routes"));
+const RouteListView = lazy(() => import("./views/route/route-list"));
+const RouteEditView = lazy(() => import("./views/route/route-edit"));
export default function AdminDashboard(props) {
@@ -81,6 +82,7 @@ export default function AdminDashboard(props) {
+ Match: {JSON.stringify(routeTestResult)} ++