removed notification + new react structure
This commit is contained in:
@@ -1,159 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Core\API {
|
||||
|
||||
use Core\Objects\Context;
|
||||
|
||||
abstract class NewsAPI extends Request {
|
||||
public function __construct(Context $context, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($context, $externalCall, $params);
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Core\API\News {
|
||||
|
||||
use Core\API\NewsAPI;
|
||||
use Core\API\Parameter\Parameter;
|
||||
use Core\API\Parameter\StringType;
|
||||
use Core\Driver\SQL\Condition\Compare;
|
||||
use Core\Objects\Context;
|
||||
use Core\Objects\DatabaseEntity\Group;
|
||||
use Core\Objects\DatabaseEntity\News;
|
||||
|
||||
class Get extends NewsAPI {
|
||||
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, [
|
||||
"since" => new Parameter("since", Parameter::TYPE_DATE_TIME, true, null),
|
||||
"limit" => new Parameter("limit", Parameter::TYPE_INT, true, 10)
|
||||
]);
|
||||
|
||||
$this->loginRequired = false;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$since = $this->getParam("since");
|
||||
$limit = $this->getParam("limit");
|
||||
if ($limit < 1 || $limit > 30) {
|
||||
return $this->createError("Limit must be in range 1-30");
|
||||
}
|
||||
|
||||
$sql = $this->context->getSQL();
|
||||
$newsQuery = News::createBuilder($sql, false)
|
||||
->limit($limit)
|
||||
->orderBy("published_at")
|
||||
->descending()
|
||||
->fetchEntities();
|
||||
|
||||
if ($since) {
|
||||
$newsQuery->where(new Compare("published_at", $since, ">="));
|
||||
}
|
||||
|
||||
$newsArray = News::findBy($newsQuery);
|
||||
$this->success = $newsArray !== null;
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->result["news"] = [];
|
||||
foreach ($newsArray as $news) {
|
||||
$newsId = $news->getId();
|
||||
$this->result["news"][$newsId] = $news->jsonSerialize();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Publish extends NewsAPI {
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, [
|
||||
"title" => new StringType("title", 128),
|
||||
"text" => new StringType("text", 1024)
|
||||
]);
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
|
||||
$news = new News();
|
||||
$news->text = $this->getParam("text");
|
||||
$news->title = $this->getParam("title");
|
||||
$news->publishedBy = $this->context->getUser();
|
||||
|
||||
$sql = $this->context->getSQL();
|
||||
$this->success = $news->save($sql);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->result["newsId"] = $news->getId();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Delete extends NewsAPI {
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, [
|
||||
"id" => new Parameter("id", Parameter::TYPE_INT)
|
||||
]);
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$sql = $this->context->getSQL();
|
||||
$currentUser = $this->context->getUser();
|
||||
|
||||
$news = News::find($sql, $this->getParam("id"));
|
||||
$this->success = ($news !== false);
|
||||
$this->lastError = $sql->getLastError();
|
||||
if (!$this->success) {
|
||||
return false;
|
||||
} else if ($news === null) {
|
||||
return $this->createError("News Post not found");
|
||||
} else if ($news->publishedBy->getId() !== $currentUser->getId() && !$currentUser->hasGroup(Group::ADMIN)) {
|
||||
return $this->createError("You do not have permissions to delete news post of other users.");
|
||||
}
|
||||
|
||||
$this->success = $news->delete($sql);
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Edit extends NewsAPI {
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, [
|
||||
"id" => new Parameter("id", Parameter::TYPE_INT),
|
||||
"title" => new StringType("title", 128),
|
||||
"text" => new StringType("text", 1024)
|
||||
]);
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$sql = $this->context->getSQL();
|
||||
$currentUser = $this->context->getUser();
|
||||
|
||||
$news = News::find($sql, $this->getParam("id"));
|
||||
$this->success = ($news !== false);
|
||||
$this->lastError = $sql->getLastError();
|
||||
if (!$this->success) {
|
||||
return false;
|
||||
} else if ($news === null) {
|
||||
return $this->createError("News Post not found");
|
||||
} else if ($news->publishedBy->getId() !== $currentUser->getId() && !$currentUser->hasGroup(Group::ADMIN)) {
|
||||
return $this->createError("You do not have permissions to edit news post of other users.");
|
||||
}
|
||||
|
||||
$news->text = $this->getParam("text");
|
||||
$news->title = $this->getParam("title");
|
||||
$this->success = $news->save($sql);
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ namespace Core\API;
|
||||
use Core\API\Parameter\StringType;
|
||||
use Core\Objects\Context;
|
||||
use Core\Objects\DatabaseEntity\Group;
|
||||
use Core\Objects\DatabaseEntity\User;
|
||||
|
||||
class Swagger extends Request {
|
||||
|
||||
@@ -26,7 +25,7 @@ class Swagger extends Request {
|
||||
$classes = [];
|
||||
$apiDirs = ["Core", "Site"];
|
||||
foreach ($apiDirs as $apiDir) {
|
||||
$basePath = realpath(WEBROOT . "/$apiDir/Api/");
|
||||
$basePath = realpath(WEBROOT . "/$apiDir/API/");
|
||||
if (!$basePath) {
|
||||
continue;
|
||||
}
|
||||
@@ -36,7 +35,7 @@ class Swagger extends Request {
|
||||
if (is_file($fullPath) && endsWith($fileName, ".class.php")) {
|
||||
require_once $fullPath;
|
||||
$apiName = explode(".", $fileName)[0];
|
||||
$className = "\\API\\$apiName";
|
||||
$className = "\\$apiDir\\API\\$apiName";
|
||||
if (!class_exists($className)) {
|
||||
var_dump("Class not exist: $className");
|
||||
continue;
|
||||
@@ -108,6 +107,7 @@ class Swagger extends Request {
|
||||
$settings = $this->context->getSettings();
|
||||
$siteName = $settings->getSiteName();
|
||||
$domain = parse_url($settings->getBaseUrl(), PHP_URL_HOST);
|
||||
$protocol = getProtocol();
|
||||
|
||||
$permissions = $this->fetchPermissions();
|
||||
|
||||
@@ -194,7 +194,7 @@ class Swagger extends Request {
|
||||
],
|
||||
"host" => $domain,
|
||||
"basePath" => "/api",
|
||||
"schemes" => ["https"],
|
||||
"schemes" => ["$protocol"],
|
||||
"paths" => $paths,
|
||||
"definitions" => $definitions
|
||||
];
|
||||
|
||||
@@ -328,37 +328,13 @@ namespace Core\API\User {
|
||||
} else {
|
||||
|
||||
$queriedUser = $user->jsonSerialize();
|
||||
|
||||
// either we are querying own info or we are support / admin
|
||||
$currentUser = $this->context->getUser();
|
||||
$canView = ($userId === $currentUser->getId() ||
|
||||
$currentUser->hasGroup(Group::ADMIN) ||
|
||||
$currentUser->hasGroup(Group::SUPPORT));
|
||||
|
||||
// full info only when we have administrative privileges, or we are querying ourselves
|
||||
$fullInfo = ($userId === $currentUser->getId() ||
|
||||
$currentUser->hasGroup(Group::ADMIN) ||
|
||||
$currentUser->hasGroup(Group::SUPPORT));
|
||||
|
||||
if (!$canView) {
|
||||
|
||||
// check if user posted something publicly
|
||||
$res = $sql->select(new JsonArrayAgg(new Column("publishedBy"), "publisherIds"))
|
||||
->from("News")
|
||||
->execute();
|
||||
$this->success = ($res !== false);
|
||||
$this->lastError = $sql->getLastError();
|
||||
if (!$this->success) {
|
||||
return false;
|
||||
} else {
|
||||
$canView = in_array($userId, json_decode($res[0]["publisherIds"], true));
|
||||
}
|
||||
}
|
||||
|
||||
if (!$canView) {
|
||||
return $this->createError("No permissions to access this user");
|
||||
}
|
||||
|
||||
if (!$fullInfo) {
|
||||
if (!$queriedUser["confirmed"]) {
|
||||
return $this->createError("No permissions to access this user");
|
||||
|
||||
@@ -21,9 +21,9 @@ class CreateDatabase extends DatabaseScript {
|
||||
]);
|
||||
|
||||
$queries[] = Group::getHandler($sql)->getInsertQuery([
|
||||
new Group(Group::ADMIN, Group::GROUPS[Group::ADMIN], "#007bff"),
|
||||
new Group(Group::ADMIN, Group::GROUPS[Group::ADMIN], "#dc3545"),
|
||||
new Group(Group::MODERATOR, Group::GROUPS[Group::MODERATOR], "#28a745"),
|
||||
new Group(Group::SUPPORT, Group::GROUPS[Group::SUPPORT], "#dc3545"),
|
||||
new Group(Group::SUPPORT, Group::GROUPS[Group::SUPPORT], "#007bff"),
|
||||
]);
|
||||
|
||||
$queries[] = $sql->createTable("Visitor")
|
||||
@@ -84,6 +84,7 @@ class CreateDatabase extends DatabaseScript {
|
||||
->addRow("Mail/Sync", array(Group::SUPPORT, Group::ADMIN), "Allows users to synchronize mails with the database")
|
||||
->addRow("Settings/get", array(Group::ADMIN), "Allows users to fetch server settings")
|
||||
->addRow("Settings/set", array(Group::ADMIN), "Allows users create, delete or modify server settings")
|
||||
->addRow("Settings/generateJWT", array(Group::ADMIN), "Allows users generate a new jwt key")
|
||||
->addRow("Stats", array(Group::ADMIN, Group::SUPPORT), "Allows users to fetch server stats")
|
||||
->addRow("User/create", array(Group::ADMIN), "Allows users to create a new user, email address does not need to be confirmed")
|
||||
->addRow("User/fetch", array(Group::ADMIN, Group::SUPPORT), "Allows users to list all registered users")
|
||||
|
||||
@@ -47,15 +47,18 @@ class Settings {
|
||||
|
||||
public function getJwtPublicKey(bool $allowPrivate = true): ?\Firebase\JWT\Key {
|
||||
if (empty($this->jwtPublicKey)) {
|
||||
// we might have a symmetric key, should we instead return the private key?
|
||||
return $allowPrivate ? new \Firebase\JWT\Key($this->jwtSecretKey, $this->jwtAlgorithm) : null;
|
||||
if ($allowPrivate && $this->jwtSecretKey) {
|
||||
// we might have a symmetric key, should we instead return the private key?
|
||||
return new \Firebase\JWT\Key($this->jwtSecretKey, $this->jwtAlgorithm);
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
return new \Firebase\JWT\Key($this->jwtPublicKey, $this->jwtAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
public function getJwtSecretKey(): \Firebase\JWT\Key {
|
||||
return new \Firebase\JWT\Key($this->jwtSecretKey, $this->jwtAlgorithm);
|
||||
public function getJwtSecretKey(): ?\Firebase\JWT\Key {
|
||||
return $this->jwtSecretKey ? new \Firebase\JWT\Key($this->jwtSecretKey, $this->jwtAlgorithm) : null;
|
||||
}
|
||||
|
||||
public function isInstalled(): bool {
|
||||
|
||||
@@ -198,15 +198,6 @@ namespace Documents\Install {
|
||||
$success = $req->execute(array("settings" => array("installation_completed" => "1")));
|
||||
if (!$success) {
|
||||
$this->errorString = $req->getLastError();
|
||||
} else {
|
||||
$req = new \Core\API\Notifications\Create($context);
|
||||
$req->execute(array(
|
||||
"title" => "Welcome",
|
||||
"message" => "Your Web-base was successfully installed. Check out the admin dashboard. Have fun!",
|
||||
"groupId" => Group::ADMIN
|
||||
)
|
||||
);
|
||||
$this->errorString = $req->getLastError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,8 +103,9 @@ class Context {
|
||||
try {
|
||||
$token = $_COOKIE['session'];
|
||||
$settings = $this->configuration->getSettings();
|
||||
$decoded = (array)JWT::decode($token, $settings->getJwtSecretKey());
|
||||
if (!is_null($decoded)) {
|
||||
$jwtKey = $settings->getJwtSecretKey();
|
||||
if ($jwtKey) {
|
||||
$decoded = (array)JWT::decode($token, $jwtKey);
|
||||
$userId = ($decoded['userId'] ?? NULL);
|
||||
$sessionId = ($decoded['sessionId'] ?? NULL);
|
||||
if (!is_null($userId) && !is_null($sessionId)) {
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Core\Objects\DatabaseEntity;
|
||||
|
||||
use Core\API\Parameter\Parameter;
|
||||
use Core\Driver\SQL\Expression\CurrentTimeStamp;
|
||||
use Core\Objects\DatabaseEntity\Attribute\DefaultValue;
|
||||
use Core\Objects\DatabaseEntity\Attribute\MaxLength;
|
||||
use Core\Objects\DatabaseEntity\Controller\DatabaseEntity;
|
||||
|
||||
class News extends DatabaseEntity {
|
||||
|
||||
public User $publishedBy;
|
||||
#[DefaultValue(CurrentTimeStamp::class)] private \DateTime $publishedAt;
|
||||
#[MaxLength(128)] public string $title;
|
||||
#[MaxLength(1024)] public string $text;
|
||||
|
||||
public function __construct(?int $id = null) {
|
||||
parent::__construct($id);
|
||||
$this->publishedAt = new \DateTime();
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array {
|
||||
return [
|
||||
"id" => $this->getId(),
|
||||
"publishedBy" => $this->publishedBy->jsonSerialize(),
|
||||
"publishedAt" => $this->publishedAt->format(Parameter::DATE_TIME_FORMAT),
|
||||
"title" => $this->title,
|
||||
"text" => $this->text
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "account.twig" %}
|
||||
{% extends "account/account_base.twig" %}
|
||||
|
||||
{% set view_title = 'Invitation' %}
|
||||
{% set view_icon = 'user-check' %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "account.twig" %}
|
||||
{% extends "account/account_base.twig" %}
|
||||
|
||||
{% set view_title = 'Confirm Email' %}
|
||||
{% set view_icon = 'user-check' %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "account.twig" %}
|
||||
{% extends "account/account_base.twig" %}
|
||||
|
||||
{% set view_title = 'Sign In' %}
|
||||
{% set view_icon = 'user-lock' %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "account.twig" %}
|
||||
{% extends "account/account_base.twig" %}
|
||||
|
||||
{% set view_title = 'Registration' %}
|
||||
{% set view_icon = 'user-plus' %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "account.twig" %}
|
||||
{% extends "account/account_base.twig" %}
|
||||
|
||||
{% set view_title = 'Resend Confirm Email' %}
|
||||
{% set view_icon = 'envelope' %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "account.twig" %}
|
||||
{% extends "account/account_base.twig" %}
|
||||
|
||||
{% set view_title = 'Reset Password' %}
|
||||
{% set view_icon = 'user-lock' %}
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
|
||||
{% block body %}
|
||||
<noscript>You need Javascript enabled to run this app</noscript>
|
||||
<div class="wrapper" id="root"></div>
|
||||
<script src="/js/admin.min.js" nonce="{{ site.csp.nonce }}"></script>
|
||||
<div class="wrapper" type="module" id="admin-panel"></div>
|
||||
<script src="/js/admin-panel/index.js" nonce="{{ site.csp.nonce }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -10,7 +10,7 @@ if (is_file($autoLoad)) {
|
||||
require_once $autoLoad;
|
||||
}
|
||||
|
||||
define("WEBBASE_VERSION", "2.3.0");
|
||||
const WEBBASE_VERSION = "2.3.0";
|
||||
|
||||
spl_autoload_extensions(".php");
|
||||
spl_autoload_register(function ($class) {
|
||||
@@ -81,7 +81,7 @@ function generateRandomString($length, $type = "ascii"): string {
|
||||
return $randomString;
|
||||
}
|
||||
|
||||
function base64url_decode($data) {
|
||||
function base64url_decode($data): bool|string {
|
||||
$base64 = strtr($data, '-_', '+/');
|
||||
return base64_decode($base64);
|
||||
}
|
||||
@@ -247,7 +247,7 @@ function getClassName($class, bool $short = true): string {
|
||||
}
|
||||
}
|
||||
|
||||
function createError($msg) {
|
||||
function createError($msg): array {
|
||||
return ["success" => false, "msg" => $msg];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user