2022-02-20 16:53:26 +01:00
|
|
|
<?php
|
|
|
|
|
2022-11-18 18:06:46 +01:00
|
|
|
namespace Core\API;
|
2022-02-20 16:53:26 +01:00
|
|
|
|
2022-11-18 18:06:46 +01:00
|
|
|
use Core\API\Parameter\StringType;
|
|
|
|
use Core\Objects\Context;
|
2022-11-20 17:13:53 +01:00
|
|
|
use Core\Objects\DatabaseEntity\Group;
|
2022-02-20 16:53:26 +01:00
|
|
|
|
|
|
|
class Swagger extends Request {
|
|
|
|
|
2022-06-20 19:52:31 +02:00
|
|
|
public function __construct(Context $context, bool $externalCall = false) {
|
|
|
|
parent::__construct($context, $externalCall, []);
|
2022-02-20 16:53:26 +01:00
|
|
|
$this->csrfTokenRequired = false;
|
|
|
|
}
|
|
|
|
|
2022-02-21 13:01:03 +01:00
|
|
|
public function _execute(): bool {
|
2022-02-20 16:53:26 +01:00
|
|
|
header("Content-Type: application/x-yaml");
|
|
|
|
header("Access-Control-Allow-Origin: *");
|
|
|
|
die($this->getDocumentation());
|
|
|
|
}
|
|
|
|
|
|
|
|
private function fetchPermissions(): array {
|
2023-01-16 21:47:23 +01:00
|
|
|
$req = new \Core\API\Permission\Fetch($this->context);
|
2022-02-20 16:53:26 +01:00
|
|
|
$this->success = $req->execute();
|
|
|
|
$permissions = [];
|
2023-01-16 21:47:23 +01:00
|
|
|
foreach ($req->getResult()["permissions"] as $permission) {
|
2022-02-20 16:53:26 +01:00
|
|
|
$permissions["/" . strtolower($permission["method"])] = $permission["groups"];
|
|
|
|
}
|
|
|
|
|
|
|
|
return $permissions;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function canView(array $requiredGroups, Request $request): bool {
|
|
|
|
if (!$request->isPublic()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-06-20 19:52:31 +02:00
|
|
|
$currentUser = $this->context->getUser();
|
2023-01-16 21:47:23 +01:00
|
|
|
$isLoggedIn = $currentUser !== null;
|
|
|
|
if (($request->loginRequired() || !empty($requiredGroups)) && !$isLoggedIn) {
|
2022-02-20 16:53:26 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// special case: hardcoded permission
|
2023-01-16 21:47:23 +01:00
|
|
|
if ($request instanceof \Core\API\Permission\Save && (!$isLoggedIn || !$currentUser->hasGroup(Group::ADMIN))) {
|
2022-02-20 16:53:26 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!empty($requiredGroups)) {
|
2022-06-20 19:52:31 +02:00
|
|
|
$userGroups = array_keys($currentUser?->getGroups() ?? []);
|
|
|
|
return !empty(array_intersect($requiredGroups, $userGroups));
|
2022-02-20 16:53:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function getDocumentation(): string {
|
|
|
|
|
2022-06-20 19:52:31 +02:00
|
|
|
$settings = $this->context->getSettings();
|
2022-02-20 16:53:26 +01:00
|
|
|
$siteName = $settings->getSiteName();
|
|
|
|
$domain = parse_url($settings->getBaseUrl(), PHP_URL_HOST);
|
2022-11-23 23:36:30 +01:00
|
|
|
$protocol = getProtocol();
|
2022-02-20 16:53:26 +01:00
|
|
|
|
|
|
|
$permissions = $this->fetchPermissions();
|
|
|
|
|
|
|
|
$definitions = [];
|
|
|
|
$paths = [];
|
|
|
|
foreach (self::getApiEndpoints() as $endpoint => $apiClass) {
|
|
|
|
$body = null;
|
|
|
|
$requiredProperties = [];
|
2022-06-20 19:52:31 +02:00
|
|
|
$apiObject = $apiClass->newInstance($this->context, false);
|
2022-02-20 16:53:26 +01:00
|
|
|
if (!$this->canView($permissions[strtolower($endpoint)] ?? [], $apiObject)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$parameters = $apiObject->getDefaultParams();
|
|
|
|
if (!empty($parameters)) {
|
|
|
|
$body = [];
|
|
|
|
foreach ($apiObject->getDefaultParams() as $param) {
|
|
|
|
$body[$param->name] = [
|
|
|
|
"type" => $param->getSwaggerTypeName(),
|
|
|
|
"default" => $param->value
|
|
|
|
];
|
|
|
|
|
|
|
|
if ($param instanceof StringType && $param->maxLength > 0) {
|
|
|
|
$body[$param->name]["maxLength"] = $param->maxLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($body[$param->name]["type"] === "string" && ($format = $param->getSwaggerFormat())) {
|
|
|
|
$body[$param->name]["format"] = $format;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$param->optional) {
|
|
|
|
$requiredProperties[] = $param->name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$bodyName = $apiClass->getShortName() . "Body";
|
|
|
|
$definitions[$bodyName] = [
|
|
|
|
"description" => "Body for $endpoint",
|
|
|
|
"properties" => $body
|
|
|
|
];
|
|
|
|
|
|
|
|
if (!empty($requiredProperties)) {
|
|
|
|
$definitions[$bodyName]["required"] = $requiredProperties;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$endPointDefinition = [
|
|
|
|
"post" => [
|
|
|
|
"produces" => ["application/json"],
|
|
|
|
"responses" => [
|
|
|
|
"200" => ["description" => ""],
|
|
|
|
"401" => ["description" => "Login or 2FA Authorization is required"],
|
|
|
|
]
|
|
|
|
]
|
|
|
|
];
|
|
|
|
|
|
|
|
if ($apiObject->isDisabled()) {
|
|
|
|
$endPointDefinition["post"]["deprecated"] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($body) {
|
|
|
|
$endPointDefinition["post"]["consumes"] = ["application/json"];
|
|
|
|
$endPointDefinition["post"]["parameters"] = [[
|
|
|
|
"in" => "body",
|
|
|
|
"name" => "body",
|
|
|
|
"required" => !empty($requiredProperties),
|
|
|
|
"schema" => ["\$ref" => "#/definitions/" . $apiClass->getShortName() . "Body"]
|
|
|
|
]];
|
|
|
|
} else if ($apiObject->isMethodAllowed("GET")) {
|
|
|
|
$endPointDefinition["get"] = $endPointDefinition["post"];
|
|
|
|
unset($endPointDefinition["post"]);
|
|
|
|
}
|
|
|
|
|
|
|
|
$paths[$endpoint] = $endPointDefinition;
|
|
|
|
}
|
|
|
|
|
|
|
|
$yamlData = [
|
|
|
|
"swagger" => "2.0",
|
|
|
|
"info" => [
|
|
|
|
"description" => "This is the Backend API-Description of $siteName",
|
|
|
|
"version" => WEBBASE_VERSION,
|
|
|
|
"title" => $siteName,
|
|
|
|
"contact" => [ "email" => "webmaster@$domain" ],
|
|
|
|
],
|
|
|
|
"host" => $domain,
|
|
|
|
"basePath" => "/api",
|
2022-11-23 23:36:30 +01:00
|
|
|
"schemes" => ["$protocol"],
|
2022-02-20 16:53:26 +01:00
|
|
|
"paths" => $paths,
|
|
|
|
"definitions" => $definitions
|
|
|
|
];
|
|
|
|
|
2022-02-20 23:17:17 +01:00
|
|
|
return \yaml_emit($yamlData);
|
2022-02-20 16:53:26 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|