diff --git a/.htaccess b/.htaccess index e23e12c..a9c317a 100644 --- a/.htaccess +++ b/.htaccess @@ -5,7 +5,7 @@ DirectorySlash Off SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 RewriteEngine On -RewriteRule ^api(/.*)?$ /index.php?api=$1 [L,QSA] +RewriteRule ^(api(/.*)?)$ /index.php?api=$1 [L,QSA] RewriteEngine On RewriteOptions AllowNoSlash diff --git a/core/Api/LogsAPI.class.php b/core/Api/LogsAPI.class.php new file mode 100644 index 0000000..5f20d58 --- /dev/null +++ b/core/Api/LogsAPI.class.php @@ -0,0 +1,118 @@ + new Parameter("since", Parameter::TYPE_DATE_TIME, true), + "severity" => new StringType("severity", 32, true, "debug") + ]); + } + + protected function _execute(): bool { + $since = $this->getParam("since"); + $sql = $this->user->getSQL(); + $severity = strtolower(trim($this->getParam("severity"))); + $shownLogLevels = Logger::LOG_LEVELS; + + $logLevel = array_search($severity, Logger::LOG_LEVELS, true); + if ($logLevel === false) { + return $this->createError("Invalid severity. Allowed values: " . implode(",", Logger::LOG_LEVELS)); + } else if ($logLevel > 0) { + $shownLogLevels = array_slice(Logger::LOG_LEVELS, $logLevel); + } + + $query = $sql->select("id", "module", "message", "severity", "timestamp") + ->from("SystemLog") + ->orderBy("timestamp") + ->descending(); + + if ($since !== null) { + $query->where(new Compare("timestamp", $since, ">=")); + } + + if ($logLevel > 0) { + $query->where(new CondIn(new Column("severity"), $shownLogLevels)); + } + + $res = $query->execute(); + $this->success = $res !== false; + $this->lastError = $sql->getLastError(); + + if ($this->success) { + $this->result["logs"] = $res; + } else { + // we couldn't fetch logs from database, return a message and proceed to log files + $this->result["logs"] = [ + [ + "id" => "fetch-fail", + "module" => "LogsAPI", + "message" => "Failed retrieving logs from database: " . $this->lastError, + "severity" => "error", + "timestamp" => (new \DateTime())->format(Parameter::DATE_TIME_FORMAT) + ] + ]; + } + + // get all log entries from filesystem (if database failed) + $logPath = realpath(implode(DIRECTORY_SEPARATOR, [WEBROOT, "core", "Logs"])); + if ($logPath) { + $index = 1; + foreach (scandir($logPath) as $fileName) { + $logFile = $logPath . DIRECTORY_SEPARATOR . $fileName; + // {module}_{severity}_{date}_{time}_{ms}.log + if (preg_match("/^(\w+)_(\w+)_((\d+-\d+-\d+_){2}\d+)\.log$/", $fileName, $matches) && is_file($logFile)) { + $content = @file_get_contents($logFile); + $date = \DateTime::createFromFormat(Logger::LOG_FILE_DATE_FORMAT, $matches[3]); + if ($content && $date) { + + // filter log date + if ($since !== null && datetimeDiff($date, $since) < 0) { + continue; + } + + // filter log level + if (!in_array(trim(strtolower($matches[2])), $shownLogLevels)) { + continue; + } + + $this->result["logs"][] = [ + "id" => "file-" . ($index++), + "module" => $matches[1], + "severity" => $matches[2], + "message" => $content, + "timestamp" => $date->format(Parameter::DATE_TIME_FORMAT) + ]; + } + } + } + } + + return true; + } + } + +} \ No newline at end of file diff --git a/core/Objects/Router/Router.class.php b/core/Objects/Router/Router.class.php index da6ba6a..6320942 100644 --- a/core/Objects/Router/Router.class.php +++ b/core/Objects/Router/Router.class.php @@ -24,7 +24,6 @@ class Router { public function run(string $url): string { // TODO: do we want a global try cache and return status page 500 on any error? - // or do we want to have a global status page function here? $url = strtok($url, "?"); foreach ($this->routes as $route) { @@ -69,6 +68,11 @@ class Router { $routes = ""; foreach ($this->routes as $route) { + // do not generate cache for static api route + if ($route instanceof ApiRoute) { + continue; + } + $constructor = $route->generateCache(); $routes .= "\n \$this->addRoute($constructor);"; } diff --git a/docker/nginx/site.conf b/docker/nginx/site.conf index 7a74ac4..d3b5344 100644 --- a/docker/nginx/site.conf +++ b/docker/nginx/site.conf @@ -11,7 +11,7 @@ server { error_page 500 /index.php?error=500; # rewrite api - rewrite ^/api(/.*)$ /index.php?api=$1; + rewrite ^/(api(/.*)?)$ /index.php?api=$1; # deny access to .gitignore / .htaccess location ~ /\.(?!well-known).* {