Merge branch 'reactjs'
This commit is contained in:
commit
fd738c46e8
11
.htaccess
11
.htaccess
@ -1,8 +1,13 @@
|
||||
php_flag display_errors on
|
||||
Options -Indexes
|
||||
|
||||
RedirectMatch 404 /\.git
|
||||
DirectorySlash Off
|
||||
|
||||
RewriteEngine On
|
||||
RewriteRule ^api/(.*)?$ index.php?api=$1&$2 [L,QSA]
|
||||
RewriteRule ^((?!((js|css|img|fonts|api)($|\/)))(.*)?)$ index.php?site=$1&$2 [L,QSA]
|
||||
RewriteRule ^api(/.*)?$ /index.php?api=$1 [L,QSA]
|
||||
|
||||
RewriteEngine On
|
||||
RewriteOptions AllowNoSlash
|
||||
RewriteRule ^((\.idea|\.git|src|test|core)(/.*)?)$ /index.php?site=$1 [L,QSA]
|
||||
|
||||
FallbackResource /index.php
|
2
.idea/.gitignore
vendored
Normal file
2
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Default ignored files
|
||||
/workspace.xml
|
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
8
.idea/dictionaries/webbase.xml
Normal file
8
.idea/dictionaries/webbase.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="webbase">
|
||||
<words>
|
||||
<w>adminlte</w>
|
||||
<w>navbar</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
6
.idea/misc.xml
Normal file
6
.idea/misc.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="JSX" />
|
||||
</component>
|
||||
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/web-base.iml" filepath="$PROJECT_DIR$/.idea/web-base.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
4
.idea/php.xml
Normal file
4
.idea/php.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="7.4" />
|
||||
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
8
.idea/web-base.iml
Normal file
8
.idea/web-base.iml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
13
README.md
13
README.md
@ -1,12 +1,19 @@
|
||||
# Web-Base
|
||||
|
||||
Web-Base is a php framework which provides basic web functionalities.
|
||||
Web-Base is a php framework which provides basic web functionalities and a modern ReactJS Admin Dashboard.
|
||||
|
||||
### Requirements
|
||||
- PHP >= 7.4
|
||||
- One of these php extensions: mysqli, postgres
|
||||
|
||||
### Current Functionalities:
|
||||
- Installation Guide with automatic database setup
|
||||
- REST API
|
||||
- Account managment
|
||||
- New: Now supporting MySQL + PostgreSQL
|
||||
- Account management
|
||||
- Supporting MySQL + PostgreSQL
|
||||
- New: Page Routing
|
||||
- New: Admin Dashboard
|
||||
- New: Account & User functions
|
||||
|
||||
### Upcoming:
|
||||
I actually don't know what i want to implement here. There are quite to many CMS out there with alot of vulnerabilities. There also exist some frameworks already. This project is meant to provide a stable project base to implement what ever a developer wants to: Dynamic Homepages, Webshops, ..
|
||||
|
@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Api\ApiKey;
|
||||
|
||||
use \Api\Request;
|
||||
class Create extends Request {
|
||||
|
||||
public function __construct($user, $externCall = false) {
|
||||
parent::__construct($user, $externCall, array());
|
||||
$this->apiKeyAllowed = false;
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$apiKey = generateRandomString(64);
|
||||
$sql = $this->user->getSQL();
|
||||
$validUntil = (new \DateTime())->modify("+30 DAY");
|
||||
|
||||
$this->success = $sql->insert("ApiKey", array("user_id", "api_key", "valid_until"))
|
||||
->addRow($this->user->getId(), $apiKey, $validUntil)
|
||||
->returning("uid")
|
||||
->execute();
|
||||
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->result["api_key"] = array(
|
||||
"api_key" => $apiKey,
|
||||
"valid_until" => $validUntil->getTimestamp(),
|
||||
"uid" => $sql->getLastInsertId(),
|
||||
);
|
||||
} else {
|
||||
$this->result["api_key"] = null;
|
||||
}
|
||||
return $this->success;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Api\ApiKey;
|
||||
|
||||
use \Api\Request;
|
||||
use \Driver\SQL\Condition\Compare;
|
||||
|
||||
class Fetch extends Request {
|
||||
|
||||
public function __construct($user, $externCall = false) {
|
||||
parent::__construct($user, $externCall, array());
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("uid", "api_key", "valid_until")
|
||||
->from("ApiKey")
|
||||
->where(new Compare("user_id", $this->user->getId()))
|
||||
->where(new Compare("valid_until", $sql->currentTimestamp(), ">"))
|
||||
->where(new Compare("active", true))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if($this->success) {
|
||||
$this->result["api_keys"] = array();
|
||||
foreach($res as $row) {
|
||||
$this->result["api_keys"][] = array(
|
||||
"uid" => $row["uid"],
|
||||
"api_key" => $row["api_key"],
|
||||
"valid_until" => (new \DateTime($row["valid_until"]))->getTimestamp(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Api\ApiKey;
|
||||
|
||||
use \Api\Request;
|
||||
use \Api\Parameter\Parameter;
|
||||
use \Driver\SQL\Condition\Compare;
|
||||
|
||||
class Refresh extends Request {
|
||||
|
||||
public function __construct($user, $externCall = false) {
|
||||
parent::__construct($user, $externCall, array(
|
||||
"id" => new Parameter("id", Parameter::TYPE_INT),
|
||||
));
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
private function apiKeyExists() {
|
||||
$id = $this->getParam("id");
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->count())
|
||||
->from("ApiKey")
|
||||
->where(new Compare("uid", $id))
|
||||
->where(new Compare("user_id", $this->user->getId()))
|
||||
->where(new Compare("valid_until", $sql->currentTimestamp(), ">"))
|
||||
->where(new Compare("active", 1))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if($this->success && $res[0]["count"] === 0) {
|
||||
$this->success = false;
|
||||
$this->lastError = "This API-Key does not exist.";
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $this->getParam("id");
|
||||
if(!$this->apiKeyExists())
|
||||
return false;
|
||||
|
||||
$validUntil = (new \DateTime)->modify("+30 DAY");
|
||||
$sql = $this->user->getSQL();
|
||||
$this->success = $sql->update("ApiKey")
|
||||
->set("valid_until", $validUntil)
|
||||
->where(new Compare("uid", $id))
|
||||
->where(new Compare("user_id", $this->user->getId()))
|
||||
->execute();
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->result["valid_until"] = $validUntil->getTimestamp();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Api\ApiKey;
|
||||
|
||||
use \Api\Request;
|
||||
use \Api\Parameter\Parameter;
|
||||
use \Driver\SQL\Condition\Compare;
|
||||
|
||||
class Revoke extends Request {
|
||||
|
||||
public function __construct($user, $externCall = false) {
|
||||
parent::__construct($user, $externCall, array(
|
||||
"id" => new Parameter("id", Parameter::TYPE_INT),
|
||||
));
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
private function apiKeyExists() {
|
||||
$id = $this->getParam("id");
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->count())
|
||||
->from("ApiKey")
|
||||
->where(new Compare("uid", $id))
|
||||
->where(new Compare("user_id", $this->user->getId()))
|
||||
->where(new Compare("valid_until", $sql->currentTimestamp(), ">"))
|
||||
->where(new Compare("active", 1))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if($this->success && $res[0]["count"] === 0) {
|
||||
$this->success = false;
|
||||
$this->lastError = "This API-Key does not exist.";
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function execute($aValues = array()) {
|
||||
if(!parent::execute($aValues)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $this->getParam("id");
|
||||
if(!$this->apiKeyExists())
|
||||
return false;
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$this->success = $sql->update("ApiKey")
|
||||
->set("active", false)
|
||||
->where(new Compare("uid", $id))
|
||||
->where(new Compare("user_id", $this->user->getId()))
|
||||
->execute();
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
187
core/Api/ApiKeyAPI.class.php
Normal file
187
core/Api/ApiKeyAPI.class.php
Normal file
@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
namespace Api {
|
||||
|
||||
use Driver\SQL\Condition\Compare;
|
||||
|
||||
abstract class ApiKeyAPI extends Request {
|
||||
|
||||
protected function apiKeyExists($id) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->count())
|
||||
->from("ApiKey")
|
||||
->where(new Compare("uid", $id))
|
||||
->where(new Compare("user_id", $this->user->getId()))
|
||||
->where(new Compare("valid_until", $sql->currentTimestamp(), ">"))
|
||||
->where(new Compare("active", 1))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if($this->success && $res[0]["count"] === 0) {
|
||||
return $this->createError("This API-Key does not exist.");
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Api\ApiKey {
|
||||
|
||||
use Api\ApiKeyAPI;
|
||||
use Api\Parameter\Parameter;
|
||||
use DateTime;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Exception;
|
||||
|
||||
class Create extends ApiKeyAPI {
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array());
|
||||
$this->apiKeyAllowed = false;
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$apiKey = generateRandomString(64);
|
||||
$sql = $this->user->getSQL();
|
||||
$validUntil = (new \DateTime())->modify("+30 DAY");
|
||||
|
||||
$this->success = $sql->insert("ApiKey", array("user_id", "api_key", "valid_until"))
|
||||
->addRow($this->user->getId(), $apiKey, $validUntil)
|
||||
->returning("uid")
|
||||
->execute();
|
||||
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->result["api_key"] = array(
|
||||
"api_key" => $apiKey,
|
||||
"valid_until" => $validUntil->getTimestamp(),
|
||||
"uid" => $sql->getLastInsertId(),
|
||||
);
|
||||
} else {
|
||||
$this->result["api_key"] = null;
|
||||
}
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Fetch extends ApiKeyAPI {
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array());
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("uid", "api_key", "valid_until")
|
||||
->from("ApiKey")
|
||||
->where(new Compare("user_id", $this->user->getId()))
|
||||
->where(new Compare("valid_until", $sql->currentTimestamp(), ">"))
|
||||
->where(new Compare("active", true))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if($this->success) {
|
||||
$this->result["api_keys"] = array();
|
||||
foreach($res as $row) {
|
||||
try {
|
||||
$validUntil = (new DateTime($row["valid_until"]))->getTimestamp();
|
||||
} catch (Exception $e) {
|
||||
$validUntil = $row["valid_until"];
|
||||
}
|
||||
|
||||
$this->result["api_keys"][] = array(
|
||||
"uid" => intval($row["uid"]),
|
||||
"api_key" => $row["api_key"],
|
||||
"valid_until" => $validUntil,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Refresh extends ApiKeyAPI {
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
"id" => new Parameter("id", Parameter::TYPE_INT),
|
||||
));
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $this->getParam("id");
|
||||
if(!$this->apiKeyExists($id))
|
||||
return false;
|
||||
|
||||
$validUntil = (new \DateTime)->modify("+30 DAY");
|
||||
$sql = $this->user->getSQL();
|
||||
$this->success = $sql->update("ApiKey")
|
||||
->set("valid_until", $validUntil)
|
||||
->where(new Compare("uid", $id))
|
||||
->where(new Compare("user_id", $this->user->getId()))
|
||||
->execute();
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->result["valid_until"] = $validUntil->getTimestamp();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Revoke extends ApiKeyAPI {
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
"id" => new Parameter("id", Parameter::TYPE_INT),
|
||||
));
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function execute($aValues = array()) {
|
||||
if(!parent::execute($aValues)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $this->getParam("id");
|
||||
if(!$this->apiKeyExists($id))
|
||||
return false;
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$this->success = $sql->update("ApiKey")
|
||||
->set("active", false)
|
||||
->where(new Compare("uid", $id))
|
||||
->where(new Compare("user_id", $this->user->getId()))
|
||||
->execute();
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
115
core/Api/ContactAPI.class.php
Normal file
115
core/Api/ContactAPI.class.php
Normal file
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace Api {
|
||||
abstract class ContactAPI extends Request {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace Api\Contact {
|
||||
|
||||
use Api\ContactAPI;
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
use Api\VerifyCaptcha;
|
||||
use Objects\User;
|
||||
|
||||
class Request extends ContactAPI {
|
||||
|
||||
private int $notificationId;
|
||||
private int $contactRequestId;
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
$parameters = array(
|
||||
'fromName' => new StringType('fromName', 32),
|
||||
'fromEmail' => new Parameter('fromEmail', Parameter::TYPE_EMAIL),
|
||||
'message' => new StringType('message', 512),
|
||||
);
|
||||
|
||||
$settings = $user->getConfiguration()->getSettings();
|
||||
if ($settings->isRecaptchaEnabled()) {
|
||||
$parameters["captcha"] = new StringType("captcha");
|
||||
}
|
||||
|
||||
parent::__construct($user, $externalCall, $parameters);
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if (!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$settings = $this->user->getConfiguration()->getSettings();
|
||||
if ($settings->isRecaptchaEnabled()) {
|
||||
$captcha = $this->getParam("captcha");
|
||||
$req = new VerifyCaptcha($this->user);
|
||||
if (!$req->execute(array("captcha" => $captcha, "action" => "contact"))) {
|
||||
return $this->createError($req->getLastError());
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->insertContactRequest()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->createNotification();
|
||||
|
||||
if (!$this->success) {
|
||||
return $this->createError("The contact request was saved, but the server was unable to create a notification.");
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function insertContactRequest() {
|
||||
$sql = $this->user->getSQL();
|
||||
$name = $this->getParam("fromName");
|
||||
$email = $this->getParam("fromEmail");
|
||||
$message = $this->getParam("message");
|
||||
|
||||
$res = $sql->insert("ContactRequest", array("from_name", "from_email", "message"))
|
||||
->addRow($name, $email, $message)
|
||||
->returning("uid")
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->contactRequestId = $sql->getLastInsertId();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function createNotification() {
|
||||
$sql = $this->user->getSQL();
|
||||
$name = $this->getParam("fromName");
|
||||
$email = $this->getParam("fromEmail");
|
||||
$message = $this->getParam("message");
|
||||
|
||||
$res = $sql->insert("Notification", array("title", "message", "type"))
|
||||
->addRow("New Contact Request from: $name", "$name ($email) wrote:\n$message", "message")
|
||||
->returning("uid")
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->notificationId = $sql->getLastInsertId();
|
||||
|
||||
$res = $sql->insert("GroupNotification", array("group_id", "notification_id"))
|
||||
->addRow(USER_GROUP_ADMIN, $this->notificationId)
|
||||
->addRow(USER_GROUP_SUPPORT, $this->notificationId)
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Api;
|
||||
|
||||
class GetLanguages extends Request {
|
||||
|
||||
public function __construct($user, $externCall = false) {
|
||||
parent::__construct($user, $externCall, array());
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("uid", "code", "name")
|
||||
->from("Language")
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if($this->success) {
|
||||
$this->result['languages'] = array();
|
||||
if(empty($res) === 0) {
|
||||
$this->lastError = L("No languages found");
|
||||
} else {
|
||||
foreach($res as $row) {
|
||||
$this->result['languages'][$row['uid']] = $row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
194
core/Api/GroupsAPI.class.php
Normal file
194
core/Api/GroupsAPI.class.php
Normal file
@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
namespace Api {
|
||||
|
||||
use Driver\SQL\Condition\Compare;
|
||||
|
||||
abstract class GroupsAPI extends Request {
|
||||
|
||||
protected function groupExists($name) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->count())
|
||||
->from("Group")
|
||||
->where(new Compare("name", $name))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success && $res[0]["count"] > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Api\Groups {
|
||||
|
||||
use Api\GroupsAPI;
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
|
||||
class Fetch extends GroupsAPI {
|
||||
|
||||
private int $groupCount;
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
'page' => new Parameter('page', Parameter::TYPE_INT, true, 1),
|
||||
'count' => new Parameter('count', Parameter::TYPE_INT, true, 20)
|
||||
));
|
||||
|
||||
$this->groupCount = 0;
|
||||
}
|
||||
|
||||
private function getGroupCount() {
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->count())->from("Group")->execute();
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->groupCount = $res[0]["count"];
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$page = $this->getParam("page");
|
||||
if($page < 1) {
|
||||
return $this->createError("Invalid page count");
|
||||
}
|
||||
|
||||
$count = $this->getParam("count");
|
||||
if($count < 1 || $count > 50) {
|
||||
return $this->createError("Invalid fetch count");
|
||||
}
|
||||
|
||||
if (!$this->getGroupCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("Group.uid as groupId", "Group.name as groupName", "Group.color as groupColor", $sql->count("UserGroup.user_id"))
|
||||
->from("Group")
|
||||
->leftJoin("UserGroup", "UserGroup.group_id", "Group.uid")
|
||||
->groupBy("Group.uid")
|
||||
->orderBy("Group.uid")
|
||||
->ascending()
|
||||
->limit($count)
|
||||
->offset(($page - 1) * $count)
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if($this->success) {
|
||||
$this->result["groups"] = array();
|
||||
foreach($res as $row) {
|
||||
$groupId = intval($row["groupId"]);
|
||||
$groupName = $row["groupName"];
|
||||
$groupColor = $row["groupColor"];
|
||||
$memberCount = $row["usergroup_user_id_count"];
|
||||
$this->result["groups"][$groupId] = array(
|
||||
"name" => $groupName,
|
||||
"memberCount" => $memberCount,
|
||||
"color" => $groupColor,
|
||||
);
|
||||
}
|
||||
$this->result["pageCount"] = intval(ceil($this->groupCount / $count));
|
||||
$this->result["totalCount"] = $this->groupCount;
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Create extends GroupsAPI {
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
'name' => new StringType('name', 32),
|
||||
'color' => new StringType('color', 10),
|
||||
));
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if (!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$name = $this->getParam("name");
|
||||
if (preg_match("/^[a-zA-Z][a-zA-Z0-9_-]*$/", $name) !== 1) {
|
||||
return $this->createError("Invalid name");
|
||||
}
|
||||
|
||||
$color = $this->getParam("color");
|
||||
if (preg_match("/^#[a-fA-F0-9]{3,6}$/", $color) !== 1) {
|
||||
return $this->createError("Invalid color");
|
||||
}
|
||||
|
||||
$exists = $this->groupExists($name);
|
||||
if (!$this->success) {
|
||||
return false;
|
||||
} else if ($exists) {
|
||||
return $this->createError("A group with this name already exists");
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->insert("Group", array("name", "color"))
|
||||
->addRow($name, $color)
|
||||
->returning("uid")
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->result["uid"] = $sql->getLastInsertId();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Delete extends GroupsAPI {
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
'uid' => new Parameter('uid', Parameter::TYPE_INT)
|
||||
));
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if (!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $this->getParam("uid");
|
||||
if (in_array($id, DEFAULT_GROUPS)) {
|
||||
return $this->createError("You cannot delete a default group.");
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->count())
|
||||
->from("Group")
|
||||
->where(new Compare("uid", $id))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success && $res[0]["count"] === 0) {
|
||||
return $this->createError("This group does not exist.");
|
||||
}
|
||||
|
||||
$res = $sql->delete("Group")->where(new Compare("uid", $id))->execute();
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
}
|
128
core/Api/LanguageAPI.class.php
Normal file
128
core/Api/LanguageAPI.class.php
Normal file
@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace Api {
|
||||
|
||||
abstract class LanguageAPI extends Request {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Api\Language {
|
||||
|
||||
use Api\LanguageAPI;
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Driver\SQL\Condition\CondOr;
|
||||
use Objects\Language;
|
||||
|
||||
class Get extends LanguageAPI {
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array());
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("uid", "code", "name")
|
||||
->from("Language")
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if($this->success) {
|
||||
$this->result['languages'] = array();
|
||||
if(empty($res) === 0) {
|
||||
$this->lastError = L("No languages found");
|
||||
} else {
|
||||
foreach($res as $row) {
|
||||
$this->result['languages'][$row['uid']] = $row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Set extends LanguageAPI {
|
||||
|
||||
private Language $language;
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
'langId' => new Parameter('langId', Parameter::TYPE_INT, true, NULL),
|
||||
'langCode' => new StringType('langCode', 5, true, NULL),
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
private function checkLanguage() {
|
||||
$langId = $this->getParam("langId");
|
||||
$langCode = $this->getParam("langCode");
|
||||
|
||||
if(is_null($langId) && is_null($langCode)) {
|
||||
return $this->createError(L("Either langId or langCode must be given"));
|
||||
}
|
||||
|
||||
$res = $this->user->getSQL()
|
||||
->select("uid", "code", "name")
|
||||
->from("Language")
|
||||
->where(new CondOr(new Compare("uid", $langId), new Compare("code", $langCode)))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $this->user->getSQL()->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
if(count($res) == 0) {
|
||||
return $this->createError(L("This Language does not exist"));
|
||||
} else {
|
||||
$row = $res[0];
|
||||
$this->language = Language::newInstance($row['uid'], $row['code'], $row['name']);
|
||||
if(!$this->language) {
|
||||
return $this->createError(L("Error while loading language"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function updateLanguage() {
|
||||
$languageId = $this->language->getId();
|
||||
$userId = $this->user->getId();
|
||||
$sql = $this->user->getSQL();
|
||||
|
||||
$this->success = $sql->update("User")
|
||||
->set("language_id", $languageId)
|
||||
->where(new Compare("uid", $userId))
|
||||
->execute();
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!$this->checkLanguage())
|
||||
return false;
|
||||
|
||||
if($this->user->isLoggedIn()) {
|
||||
$this->updateLanguage();
|
||||
}
|
||||
|
||||
$this->user->setLanguage($this->language);
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
120
core/Api/MailAPI.class.php
Normal file
120
core/Api/MailAPI.class.php
Normal file
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace Api {
|
||||
abstract class MailAPI extends Request {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace Api\Mail {
|
||||
|
||||
use Api\MailAPI;
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
use External\PHPMailer\Exception;
|
||||
use External\PHPMailer\PHPMailer;
|
||||
use Objects\ConnectionData;
|
||||
use Objects\User;
|
||||
|
||||
class Test extends MailAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
"receiver" => new Parameter("receiver", Parameter::TYPE_EMAIL)
|
||||
));
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if (!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$receiver = $this->getParam("receiver");
|
||||
$req = new \Api\Mail\Send($this->user);
|
||||
$this->success = $req->execute(array(
|
||||
"to" => $receiver,
|
||||
"subject" => "Test E-Mail",
|
||||
"body" => "Hey! If you receive this e-mail, your mail configuration seems to be working."
|
||||
));
|
||||
|
||||
$this->lastError = $req->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Send extends MailAPI {
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
'to' => new Parameter('to', Parameter::TYPE_EMAIL),
|
||||
'subject' => new StringType('subject', -1),
|
||||
'body' => new StringType('body', -1),
|
||||
));
|
||||
$this->isPublic = false;
|
||||
}
|
||||
|
||||
private function getMailConfig() : ?ConnectionData {
|
||||
$req = new \Api\Settings\Get($this->user);
|
||||
$this->success = $req->execute(array("key" => "^mail_"));
|
||||
$this->lastError = $req->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$settings = $req->getResult()["settings"];
|
||||
|
||||
if (!isset($settings["mail_enabled"]) || $settings["mail_enabled"] !== "1") {
|
||||
$this->createError("Mail is not configured yet.");
|
||||
return null;
|
||||
}
|
||||
|
||||
$host = $settings["mail_host"] ?? "localhost";
|
||||
$port = intval($settings["mail_port"] ?? "25");
|
||||
$login = $settings["mail_username"] ?? "";
|
||||
$password = $settings["mail_password"] ?? "";
|
||||
$connectionData = new ConnectionData($host, $port, $login, $password);
|
||||
$connectionData->setProperty("from", $settings["mail_from"] ?? "");
|
||||
return $connectionData;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$mailConfig = $this->getMailConfig();
|
||||
if (!$this->success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$mail = new PHPMailer;
|
||||
$mail->IsSMTP();
|
||||
$mail->setFrom($mailConfig->getProperty("from"));
|
||||
$mail->addAddress($this->getParam('to'));
|
||||
$mail->Subject = $this->getParam('subject');
|
||||
$mail->SMTPDebug = 0;
|
||||
$mail->Host = $mailConfig->getHost();
|
||||
$mail->Port = $mailConfig->getPort();
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = $mailConfig->getLogin();
|
||||
$mail->Password = $mailConfig->getPassword();
|
||||
$mail->SMTPSecure = 'tls';
|
||||
$mail->IsHTML(true);
|
||||
$mail->CharSet = 'UTF-8';
|
||||
$mail->Body = $this->getParam('body');
|
||||
|
||||
$this->success = @$mail->Send();
|
||||
if (!$this->success) {
|
||||
$this->lastError = "Error sending Mail: $mail->ErrorInfo";
|
||||
error_log("sendMail() failed: $mail->ErrorInfo");
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->success = false;
|
||||
$this->lastError = "Error sending Mail: $e";
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Api\Notifications;
|
||||
|
||||
use \Api\Request;
|
||||
use \Api\Parameter\Parameter;
|
||||
use \Api\Parameter\StringType;
|
||||
use \Driver\SQL\Condition\Compare;
|
||||
|
||||
class Create extends Request {
|
||||
|
||||
public function __construct($user, $externCall = false) {
|
||||
parent::__construct($user, $externCall, array(
|
||||
'groupId' => new Parameter('groupId', Parameter::TYPE_INT, true),
|
||||
'userId' => new Parameter('userId', Parameter::TYPE_INT, true),
|
||||
'title' => new StringType('title', 32),
|
||||
'message' => new StringType('message', 256),
|
||||
));
|
||||
$this->isPublic = false;
|
||||
}
|
||||
|
||||
private function checkUser($userId) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->count())
|
||||
->from("User")
|
||||
->where(new Compare("uid", $userId))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
if ($res[0]["count"] == 0) {
|
||||
$this->success = false;
|
||||
$this->lastError = "User not found";
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function insertUserNotification($userId, $notificationId) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->insert("UserNotification", array("user_id", "notification_id"))
|
||||
->addRow($userId, $notificationId)
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function checkGroup($groupId) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->count())
|
||||
->from("Group")
|
||||
->where(new Compare("uid", $groupId))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
if ($res[0]["count"] == 0) {
|
||||
$this->success = false;
|
||||
$this->lastError = "Group not found";
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function insertGroupNotification($groupId, $notificationId) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->insert("GroupNotification", array("group_id", "notification_id"))
|
||||
->addRow($groupId, $notificationId)
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function createNotification($title, $message) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->insert("Notification", array("title", "message"))
|
||||
->addRow($title, $message)
|
||||
->returning("uid")
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
return $sql->getLastInsertId();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$userId = $this->getParam("userId");
|
||||
$groupId = $this->getParam("groupId");
|
||||
$title = $this->getParam("title");
|
||||
$message = $this->getParam("message");
|
||||
|
||||
if (is_null($userId) && is_null($groupId)) {
|
||||
return $this->createError("Either userId or groupId must be specified.");
|
||||
} else if(!is_null($userId) && !is_null($groupId)) {
|
||||
return $this->createError("Only one of userId and groupId must be specified.");
|
||||
} else if(!is_null($userId)) {
|
||||
if ($this->checkUser($userId)) {
|
||||
$id = $this->createNotification($title, $message);
|
||||
if ($this->success) {
|
||||
return $this->insertUserNotification($userId, $id);
|
||||
}
|
||||
}
|
||||
} else if(!is_null($groupId)) {
|
||||
if ($this->checkGroup($groupId)) {
|
||||
$id = $this->createNotification($title, $message);
|
||||
if ($this->success) {
|
||||
return $this->insertGroupNotification($groupId, $id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
@ -1,94 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Api\Notifications;
|
||||
|
||||
use \Api\Request;
|
||||
use \Driver\SQL\Condition\Compare;
|
||||
|
||||
class Fetch extends Request {
|
||||
|
||||
private $notifications;
|
||||
|
||||
public function __construct($user, $externCall = false) {
|
||||
parent::__construct($user, $externCall, array());
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
private function fetchUserNotifications() {
|
||||
$userId = $this->user->getId();
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->distinct("Notification.uid"), "created_at", "title", "message")
|
||||
->from("Notification")
|
||||
->innerJoin("UserNotification", "UserNotification.notification_id", "Notification.uid")
|
||||
->where(new Compare("UserNotification.user_id", $userId))
|
||||
->where(new Compare("UserNotification.seen", false))
|
||||
->orderBy("created_at")->descending()
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
foreach($res as $row) {
|
||||
$id = $row["uid"];
|
||||
if (!isset($this->notifications[$id])) {
|
||||
$this->notifications[$id] = array(
|
||||
"uid" => $id,
|
||||
"title" => $row["title"],
|
||||
"message" => $row["message"],
|
||||
"created_at" => $row["created_at"],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function fetchGroupNotifications() {
|
||||
$userId = $this->user->getId();
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->distinct("Notification.uid"), "created_at", "title", "message")
|
||||
->from("Notification")
|
||||
->innerJoin("GroupNotification", "GroupNotification.notification_id", "Notification.uid")
|
||||
->innerJoin("UserGroup", "GroupNotification.group_id", "UserGroup.group_id")
|
||||
->where(new Compare("UserGroup.user_id", $userId))
|
||||
->where(new Compare("GroupNotification.seen", false))
|
||||
->orderBy("created_at")->descending()
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
foreach($res as $row) {
|
||||
$id = $row["uid"];
|
||||
if (!isset($this->notifications[$id])) {
|
||||
$this->notifications[$id] = array(
|
||||
"uid" => $id,
|
||||
"title" => $row["title"],
|
||||
"message" => $row["message"],
|
||||
"created_at" => $row["created_at"],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->notifications = array();
|
||||
if ($this->fetchUserNotifications() && $this->fetchGroupNotifications()) {
|
||||
$this->result["notifications"] = $this->notifications;
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
268
core/Api/NotificationsAPI.class.php
Normal file
268
core/Api/NotificationsAPI.class.php
Normal file
@ -0,0 +1,268 @@
|
||||
<?php
|
||||
|
||||
namespace Api {
|
||||
abstract class NotificationsAPI extends Request {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace Api\Notifications {
|
||||
|
||||
use Api\NotificationsAPI;
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Driver\SQL\Condition\CondIn;
|
||||
use Driver\SQL\Query\Select;
|
||||
use Objects\User;
|
||||
|
||||
class Create extends NotificationsAPI {
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
'groupId' => new Parameter('groupId', Parameter::TYPE_INT, true),
|
||||
'userId' => new Parameter('userId', Parameter::TYPE_INT, true),
|
||||
'title' => new StringType('title', 32),
|
||||
'message' => new StringType('message', 256),
|
||||
));
|
||||
$this->isPublic = false;
|
||||
}
|
||||
|
||||
private function checkUser($userId) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->count())
|
||||
->from("User")
|
||||
->where(new Compare("uid", $userId))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
if ($res[0]["count"] == 0) {
|
||||
$this->success = false;
|
||||
$this->lastError = "User not found";
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function insertUserNotification($userId, $notificationId) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->insert("UserNotification", array("user_id", "notification_id"))
|
||||
->addRow($userId, $notificationId)
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function checkGroup($groupId) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->count())
|
||||
->from("Group")
|
||||
->where(new Compare("uid", $groupId))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
if ($res[0]["count"] == 0) {
|
||||
$this->success = false;
|
||||
$this->lastError = "Group not found";
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function insertGroupNotification($groupId, $notificationId) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->insert("GroupNotification", array("group_id", "notification_id"))
|
||||
->addRow($groupId, $notificationId)
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function createNotification($title, $message) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->insert("Notification", array("title", "message"))
|
||||
->addRow($title, $message)
|
||||
->returning("uid")
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
return $sql->getLastInsertId();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$userId = $this->getParam("userId");
|
||||
$groupId = $this->getParam("groupId");
|
||||
$title = $this->getParam("title");
|
||||
$message = $this->getParam("message");
|
||||
|
||||
if (is_null($userId) && is_null($groupId)) {
|
||||
return $this->createError("Either userId or groupId must be specified.");
|
||||
} else if(!is_null($userId) && !is_null($groupId)) {
|
||||
return $this->createError("Only one of userId and groupId must be specified.");
|
||||
} else if(!is_null($userId)) {
|
||||
if ($this->checkUser($userId)) {
|
||||
$id = $this->createNotification($title, $message);
|
||||
if ($this->success) {
|
||||
return $this->insertUserNotification($userId, $id);
|
||||
}
|
||||
}
|
||||
} else if(!is_null($groupId)) {
|
||||
if ($this->checkGroup($groupId)) {
|
||||
$id = $this->createNotification($title, $message);
|
||||
if ($this->success) {
|
||||
return $this->insertGroupNotification($groupId, $id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Fetch extends NotificationsAPI {
|
||||
|
||||
private array $notifications;
|
||||
private array $notificationids;
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
'new' => new Parameter('new', Parameter::TYPE_BOOLEAN, true, true)
|
||||
));
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
private function fetchUserNotifications() {
|
||||
$onlyNew = $this->getParam('new');
|
||||
$userId = $this->user->getId();
|
||||
$sql = $this->user->getSQL();
|
||||
$query = $sql->select($sql->distinct("Notification.uid"), "created_at", "title", "message", "type")
|
||||
->from("Notification")
|
||||
->innerJoin("UserNotification", "UserNotification.notification_id", "Notification.uid")
|
||||
->where(new Compare("UserNotification.user_id", $userId))
|
||||
->orderBy("created_at")->descending();
|
||||
|
||||
if ($onlyNew) {
|
||||
$query->where(new Compare("UserNotification.seen", false));
|
||||
}
|
||||
|
||||
return $this->fetchNotifications($query);
|
||||
}
|
||||
|
||||
private function fetchGroupNotifications() {
|
||||
$onlyNew = $this->getParam('new');
|
||||
$userId = $this->user->getId();
|
||||
$sql = $this->user->getSQL();
|
||||
$query = $sql->select($sql->distinct("Notification.uid"), "created_at", "title", "message", "type")
|
||||
->from("Notification")
|
||||
->innerJoin("GroupNotification", "GroupNotification.notification_id", "Notification.uid")
|
||||
->innerJoin("UserGroup", "GroupNotification.group_id", "UserGroup.group_id")
|
||||
->where(new Compare("UserGroup.user_id", $userId))
|
||||
->orderBy("created_at")->descending();
|
||||
|
||||
if ($onlyNew) {
|
||||
$query->where(new Compare("GroupNotification.seen", false));
|
||||
}
|
||||
|
||||
return $this->fetchNotifications($query);
|
||||
}
|
||||
|
||||
private function fetchNotifications(Select $query) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $query->execute();
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
foreach($res as $row) {
|
||||
$id = $row["uid"];
|
||||
if (!in_array($id, $this->notificationids)) {
|
||||
$this->notificationids[] = $id;
|
||||
$this->notifications[] = array(
|
||||
"uid" => $id,
|
||||
"title" => $row["title"],
|
||||
"message" => $row["message"],
|
||||
"created_at" => $row["created_at"],
|
||||
"type" => $row["type"]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->notifications = array();
|
||||
$this->notificationids = array();
|
||||
if ($this->fetchUserNotifications() && $this->fetchGroupNotifications()) {
|
||||
$this->result["notifications"] = $this->notifications;
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Seen extends NotificationsAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array());
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if (!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->update("UserNotification")
|
||||
->set("seen", true)
|
||||
->where(new Compare("user_id", $this->user->getId()))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$res = $sql->update("GroupNotification")
|
||||
->set("seen", true)
|
||||
->where(new CondIn("group_id",
|
||||
$sql->select("group_id")
|
||||
->from("UserGroup")
|
||||
->where(new Compare("user_id", $this->user->getId()))))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Api\Parameter;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class Parameter {
|
||||
const TYPE_INT = 0;
|
||||
const TYPE_FLOAT = 1;
|
||||
@ -14,15 +16,17 @@ class Parameter {
|
||||
|
||||
// only internal access
|
||||
const TYPE_RAW = 8;
|
||||
|
||||
// only json will work here i guess
|
||||
const TYPE_ARRAY = 9;
|
||||
|
||||
const names = array('Integer', 'Float', 'Boolean', 'String', 'Date', 'Time', 'DateTime', 'E-Mail', 'Raw', 'Array');
|
||||
|
||||
public $name;
|
||||
public string $name;
|
||||
public $value;
|
||||
public $optional;
|
||||
public $type;
|
||||
public $typeName;
|
||||
public int $type;
|
||||
public string $typeName;
|
||||
|
||||
public function __construct($name, $type, $optional = FALSE, $defaultValue = NULL) {
|
||||
$this->name = $name;
|
||||
@ -59,11 +63,11 @@ class Parameter {
|
||||
return Parameter::TYPE_BOOLEAN;
|
||||
else if(is_a($value, 'DateTime'))
|
||||
return Parameter::TYPE_DATE_TIME;
|
||||
else if(($d = \DateTime::createFromFormat('Y-m-d', $value)) && $d->format('Y-m-d') === $value)
|
||||
else if(($d = DateTime::createFromFormat('Y-m-d', $value)) && $d->format('Y-m-d') === $value)
|
||||
return Parameter::TYPE_DATE;
|
||||
else if(($d = \DateTime::createFromFormat('H:i:s', $value)) && $d->format('H:i:s') === $value)
|
||||
else if(($d = DateTime::createFromFormat('H:i:s', $value)) && $d->format('H:i:s') === $value)
|
||||
return Parameter::TYPE_TIME;
|
||||
else if(($d = \DateTime::createFromFormat('Y-m-d H:i:s', $value)) && $d->format('Y-m-d H:i:s') === $value)
|
||||
else if(($d = DateTime::createFromFormat('Y-m-d H:i:s', $value)) && $d->format('Y-m-d H:i:s') === $value)
|
||||
return Parameter::TYPE_DATE_TIME;
|
||||
else if (filter_var($value, FILTER_VALIDATE_EMAIL))
|
||||
return Parameter::TYPE_EMAIL;
|
||||
@ -156,6 +160,4 @@ class Parameter {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
@ -4,10 +4,10 @@ namespace Api\Parameter;
|
||||
|
||||
class StringType extends Parameter {
|
||||
|
||||
public $maxLength;
|
||||
public int $maxLength;
|
||||
public function __construct($name, $maxLength = -1, $optional = FALSE, $defaultValue = NULL) {
|
||||
parent::__construct($name, Parameter::TYPE_STRING, $optional, $defaultValue);
|
||||
$this->maxLength = $maxLength;
|
||||
parent::__construct($name, Parameter::TYPE_STRING, $optional, $defaultValue);
|
||||
}
|
||||
|
||||
public function parseParam($value) {
|
||||
@ -38,6 +38,4 @@ class StringType extends Parameter {
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
213
core/Api/PermissionAPI.class.php
Normal file
213
core/Api/PermissionAPI.class.php
Normal file
@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
namespace Api {
|
||||
|
||||
abstract class PermissionAPI extends Request {
|
||||
protected function checkStaticPermission() {
|
||||
if (!$this->user->isLoggedIn() || !$this->user->hasGroup(USER_GROUP_ADMIN)) {
|
||||
return $this->createError("Permission denied.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Api\Permission {
|
||||
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
use Api\PermissionAPI;
|
||||
use Driver\SQL\Column\Column;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Driver\SQL\Condition\CondIn;
|
||||
use Driver\SQL\Condition\CondNot;
|
||||
use Driver\SQL\Strategy\UpdateStrategy;
|
||||
use Objects\User;
|
||||
|
||||
class Check extends PermissionAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
'method' => new StringType('method', 323)
|
||||
));
|
||||
|
||||
$this->isPublic = false;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if (!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$method = $this->getParam("method");
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("groups")
|
||||
->from("ApiPermission")
|
||||
->where(new Compare("method", $method))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
if (empty($res)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$groups = json_decode($res[0]["groups"]);
|
||||
if (empty($groups)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$this->user->isLoggedIn() || empty(array_intersect($groups, array_keys($this->user->getGroups())))) {
|
||||
header('HTTP 1.1 401 Unauthorized');
|
||||
return $this->createError("Permission denied.");
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Fetch extends PermissionAPI {
|
||||
|
||||
private array $groups;
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array());
|
||||
}
|
||||
|
||||
private function fetchGroups() {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("uid", "name", "color")
|
||||
->from("Group")
|
||||
->orderBy("uid")
|
||||
->ascending()
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->groups = array();
|
||||
foreach($res as $row) {
|
||||
$groupId = $row["uid"];
|
||||
$groupName = $row["name"];
|
||||
$groupColor = $row["color"];
|
||||
$this->groups[$groupId] = array("name" => $groupName, "color" => $groupColor);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if (!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->checkStaticPermission()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->fetchGroups()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("method", "groups", "description")
|
||||
->from("ApiPermission")
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$permissions = array();
|
||||
foreach ($res as $row) {
|
||||
$method = $row["method"];
|
||||
$description = $row["description"];
|
||||
$groups = json_decode($row["groups"]);
|
||||
$permissions[] = array(
|
||||
"method" => $method,
|
||||
"groups" => $groups,
|
||||
"description" => $description
|
||||
);
|
||||
}
|
||||
$this->result["permissions"] = $permissions;
|
||||
$this->result["groups"] = $this->groups;
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Save extends PermissionAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
'permissions' => new Parameter('permissions', Parameter::TYPE_ARRAY)
|
||||
));
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if (!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->checkStaticPermission()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$permissions = $this->getParam("permissions");
|
||||
$sql = $this->user->getSQL();
|
||||
$methodParam = new StringType('method', 32);
|
||||
$groupsParam = new Parameter('groups', Parameter::TYPE_ARRAY);
|
||||
|
||||
$updateQuery = $sql->insert("ApiPermission", array("method", "groups"))
|
||||
->onDuplicateKeyStrategy(new UpdateStrategy(array("method"), array( "groups" => new Column("groups") )));
|
||||
|
||||
$insertedMethods = array();
|
||||
|
||||
foreach($permissions as $permission) {
|
||||
if (!is_array($permission)) {
|
||||
return $this->createError("Invalid data type found in parameter: permissions, expected: object");
|
||||
} else if(!isset($permission["method"]) || !array_key_exists("groups", $permission)) {
|
||||
return $this->createError("Invalid object found in parameter: permissions, expected keys 'method' and 'groups'");
|
||||
} else if (!$methodParam->parseParam($permission["method"])) {
|
||||
$expectedType = $methodParam->getTypeName();
|
||||
return $this->createError("Invalid data type found for attribute 'method', expected: $expectedType");
|
||||
} else if(!$groupsParam->parseParam($permission["groups"])) {
|
||||
$expectedType = $groupsParam->getTypeName();
|
||||
return $this->createError("Invalid data type found for attribute 'groups', expected: $expectedType");
|
||||
} else if(empty(trim($methodParam->value))) {
|
||||
return $this->createError("Method cannot be empty.");
|
||||
} else {
|
||||
$method = $methodParam->value;
|
||||
$groups = $groupsParam->value;
|
||||
$updateQuery->addRow($method, $groups);
|
||||
$insertedMethods[] = $method;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($permissions)) {
|
||||
$res = $updateQuery->execute();
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
}
|
||||
|
||||
if ($this->success) {
|
||||
$res = $sql->delete("ApiPermission")
|
||||
->where(new Compare("description", "")) // only delete non default permissions
|
||||
->where(new CondNot(new CondIn("method", $insertedMethods)))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,36 +2,41 @@
|
||||
|
||||
namespace Api;
|
||||
|
||||
use Objects\User;
|
||||
|
||||
class Request {
|
||||
|
||||
protected $user;
|
||||
protected $params;
|
||||
protected $lastError;
|
||||
protected $result;
|
||||
protected $success;
|
||||
protected $isPublic;
|
||||
protected $loginRequired;
|
||||
protected $variableParamCount;
|
||||
protected $isDisabled;
|
||||
protected $apiKeyAllowed;
|
||||
protected User $user;
|
||||
protected array $params;
|
||||
protected string $lastError;
|
||||
protected array $result;
|
||||
protected bool $success;
|
||||
protected bool $isPublic;
|
||||
protected bool $loginRequired;
|
||||
protected bool $variableParamCount;
|
||||
protected bool $isDisabled;
|
||||
protected bool $apiKeyAllowed;
|
||||
protected bool $csrfTokenRequired;
|
||||
|
||||
private $aDefaultParams;
|
||||
private $allowedMethods;
|
||||
private $externCall;
|
||||
private array $aDefaultParams;
|
||||
private array $allowedMethods;
|
||||
private bool $externalCall;
|
||||
|
||||
public function __construct($user, $externCall = false, $params = array()) {
|
||||
public function __construct(User $user, bool $externalCall = false, array $params = array()) {
|
||||
$this->user = $user;
|
||||
$this->aDefaultParams = $params;
|
||||
$this->lastError = '';
|
||||
|
||||
$this->success = false;
|
||||
$this->result = array();
|
||||
$this->externCall = $externCall;
|
||||
$this->externalCall = $externalCall;
|
||||
$this->isPublic = true;
|
||||
$this->isDisabled = false;
|
||||
$this->loginRequired = false;
|
||||
$this->variableParamCount = false;
|
||||
$this->apiKeyAllowed = true;
|
||||
$this->allowedMethods = array("GET", "POST");
|
||||
$this->lastError = "";
|
||||
$this->csrfTokenRequired = true;
|
||||
}
|
||||
|
||||
protected function forbidMethod($method) {
|
||||
@ -40,33 +45,20 @@ class Request {
|
||||
}
|
||||
}
|
||||
|
||||
public function getParamsString() {
|
||||
$str = "";
|
||||
$count = count($this->params);
|
||||
$i = 0;
|
||||
foreach($this->params as $param) {
|
||||
$str .= $param->toString();
|
||||
if($i < $count - 1) $str .= ", ";
|
||||
$i++;
|
||||
}
|
||||
|
||||
return "($str)";
|
||||
}
|
||||
|
||||
public function parseParams($values) {
|
||||
foreach($this->params as $name => $param) {
|
||||
$value = (isset($values[$name]) ? $values[$name] : NULL);
|
||||
|
||||
if(!$param->optional && is_null($value)) {
|
||||
$this->lastError = 'Missing parameter: ' . $name;
|
||||
return false;
|
||||
foreach($this->params as $name => $param) {
|
||||
$value = $values[$name] ?? NULL;
|
||||
|
||||
$isEmpty = (is_string($value) || is_array($value)) && empty($value);
|
||||
if(!$param->optional && (is_null($value) || $isEmpty)) {
|
||||
return $this->createError("Missing parameter: $name");
|
||||
}
|
||||
|
||||
if(!is_null($value)) {
|
||||
if(!is_null($value) && !$isEmpty) {
|
||||
if(!$param->parseParam($value)) {
|
||||
$value = print_r($value, true);
|
||||
$this->lastError = "Invalid Type for parameter: $name '$value' (Required: " . $param->getTypeName() . ")";
|
||||
return false;
|
||||
return $this->createError("Invalid Type for parameter: $name '$value' (Required: " . $param->getTypeName() . ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -93,11 +85,17 @@ class Request {
|
||||
$this->result['logoutIn'] = $this->user->getSession()->getExpiresSeconds();
|
||||
}
|
||||
|
||||
if($this->externCall) {
|
||||
if($this->externalCall) {
|
||||
$values = $_REQUEST;
|
||||
if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_SERVER["CONTENT_TYPE"]) && in_array("application/json", explode(";", $_SERVER["CONTENT_TYPE"]))) {
|
||||
$jsonData = json_decode(file_get_contents('php://input'), true);
|
||||
$values = array_merge($values, $jsonData);
|
||||
if ($jsonData) {
|
||||
$values = array_merge($values, $jsonData);
|
||||
} else {
|
||||
$this->lastError = 'Invalid request body.';
|
||||
header('HTTP 1.1 400 Bad Request');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,7 +104,7 @@ class Request {
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->externCall && !$this->isPublic) {
|
||||
if($this->externalCall && !$this->isPublic) {
|
||||
$this->lastError = 'This function is private.';
|
||||
header('HTTP 1.1 403 Forbidden');
|
||||
return false;
|
||||
@ -118,18 +116,42 @@ class Request {
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->externalCall) {
|
||||
$apiKeyAuthorized = false;
|
||||
|
||||
if($this->loginRequired) {
|
||||
$authorized = false;
|
||||
if(isset($values['api_key']) && $this->apiKeyAllowed) {
|
||||
$apiKey = $values['api_key'];
|
||||
$authorized = $this->user->authorize($apiKey);
|
||||
// Logged in or api key authorized?
|
||||
if ($this->loginRequired) {
|
||||
if(isset($values['api_key']) && $this->apiKeyAllowed) {
|
||||
$apiKey = $values['api_key'];
|
||||
$apiKeyAuthorized = $this->user->authorize($apiKey);
|
||||
}
|
||||
|
||||
if(!$this->user->isLoggedIn() && !$apiKeyAuthorized) {
|
||||
$this->lastError = 'You are not logged in.';
|
||||
header('HTTP 1.1 401 Unauthorized');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$this->user->isLoggedIn() && !$authorized) {
|
||||
$this->lastError = 'You are not logged in.';
|
||||
header('HTTP 1.1 401 Unauthorized');
|
||||
return false;
|
||||
// CSRF Token
|
||||
if($this->csrfTokenRequired && $this->user->isLoggedIn()) {
|
||||
// csrf token required + external call
|
||||
// if it's not a call with API_KEY, check for csrf_token
|
||||
if (!isset($values["csrf_token"]) || strcmp($values["csrf_token"], $this->user->getSession()->getCsrfToken()) !== 0) {
|
||||
$this->lastError = "CSRF-Token mismatch";
|
||||
header('HTTP 1.1 403 Forbidden');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for permission
|
||||
if (!($this instanceof \Api\Permission\Save)) {
|
||||
$req = new \Api\Permission\Check($this->user);
|
||||
$this->success = $req->execute(array("method" => $this->getMethod()));
|
||||
$this->lastError = $req->getLastError();
|
||||
if (!$this->success) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,47 +171,32 @@ class Request {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isValidString($str, $regex) {
|
||||
return preg_replace($regex, "", $str) === $str;
|
||||
}
|
||||
|
||||
protected function createError($err) {
|
||||
$this->success = false;
|
||||
$this->lastError = $err;
|
||||
return false;
|
||||
}
|
||||
//
|
||||
// public static function callDirectly($class, $db) {
|
||||
// header('Content-Type: application/json');
|
||||
// require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/api/objects/User.php';
|
||||
// require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/sql.php';
|
||||
// require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/conf/sql.php';
|
||||
//
|
||||
// $sql = connectSQL(getSqlData($db));
|
||||
// $user = new CUser($sql);
|
||||
// $request = new $class($user, true);
|
||||
// $request->execute();
|
||||
// $sql->close();
|
||||
// $user->sendCookies();
|
||||
// return $request->getJsonResult();
|
||||
// }
|
||||
|
||||
protected function getParam($name) { return isset($this->params[$name]) ? $this->params[$name]->value : NULL; }
|
||||
protected function getParam($name) {
|
||||
return isset($this->params[$name]) ? $this->params[$name]->value : NULL;
|
||||
}
|
||||
|
||||
public function isPublic() { return $this->isPublic; }
|
||||
public function getDescription() { return ''; }
|
||||
public function getSection() { return 'Default'; }
|
||||
public function getLastError() { return $this->lastError; }
|
||||
public function getResult() { return $this->result; }
|
||||
public function success() { return $this->success; }
|
||||
public function loginRequired() { return $this->loginRequired; }
|
||||
public function isExternCall() { return $this->externCall; }
|
||||
public function isExternalCall() { return $this->externalCall; }
|
||||
|
||||
private function getMethod() {
|
||||
$class = str_replace("\\", "/", get_class($this));
|
||||
$class = substr($class, strlen("api/"));
|
||||
return $class;
|
||||
}
|
||||
|
||||
public function getJsonResult() {
|
||||
$this->result['success'] = $this->success;
|
||||
$this->result['msg'] = $this->lastError;
|
||||
return json_encode($this->result);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
?>
|
||||
}
|
217
core/Api/RoutesAPI.class.php
Normal file
217
core/Api/RoutesAPI.class.php
Normal file
@ -0,0 +1,217 @@
|
||||
<?php
|
||||
|
||||
namespace Api {
|
||||
abstract class RoutesAPI extends Request {
|
||||
|
||||
protected function formatRegex(string $input, bool $append) : string {
|
||||
$start = startsWith($input, "^");
|
||||
$end = endsWith($input, "$");
|
||||
if ($append) {
|
||||
if (!$start) $input = "^$input";
|
||||
if (!$end) $input = "$input$";
|
||||
} else {
|
||||
if ($start) $input = substr($input, 1);
|
||||
if ($end) $input = substr($input, 0, strlen($input)-1);
|
||||
}
|
||||
|
||||
return $input;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Api\Routes {
|
||||
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
use Api\RoutesAPI;
|
||||
use Driver\SQL\Column\Column;
|
||||
use Driver\SQL\Condition\CondBool;
|
||||
use Driver\SQL\Condition\CondRegex;
|
||||
|
||||
class Fetch extends RoutesAPI {
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array());
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
|
||||
$res = $sql
|
||||
->select("uid", "request", "action", "target", "extra", "active")
|
||||
->from("Route")
|
||||
->orderBy("uid")
|
||||
->ascending()
|
||||
->execute();
|
||||
|
||||
$this->lastError = $sql->getLastError();
|
||||
$this->success = ($res !== FALSE);
|
||||
|
||||
if ($this->success) {
|
||||
$routes = array();
|
||||
foreach($res as $row) {
|
||||
$routes[] = array(
|
||||
"uid" => intval($row["uid"]),
|
||||
"request" => $this->formatRegex($row["request"], false),
|
||||
"action" => $row["action"],
|
||||
"target" => $row["target"],
|
||||
"extra" => $row["extra"] ?? "",
|
||||
"active" => intval($sql->parseBool($row["active"])),
|
||||
);
|
||||
}
|
||||
|
||||
$this->result["routes"] = $routes;
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Find extends RoutesAPI {
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
'request' => new StringType('request', 128, true, '/')
|
||||
));
|
||||
|
||||
$this->isPublic = false;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$request = $this->getParam('request');
|
||||
if (!startsWith($request, '/')) {
|
||||
$request = "/$request";
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
|
||||
$res = $sql
|
||||
->select("uid", "request", "action", "target", "extra")
|
||||
->from("Route")
|
||||
->where(new CondBool("active"))
|
||||
->where(new CondRegex($request, new Column("request")))
|
||||
->limit(1)
|
||||
->execute();
|
||||
|
||||
$this->lastError = $sql->getLastError();
|
||||
$this->success = ($res !== FALSE);
|
||||
|
||||
if ($this->success) {
|
||||
if (!empty($res)) {
|
||||
$row = $res[0];
|
||||
$this->result["route"] = array(
|
||||
"uid" => intval($row["uid"]),
|
||||
"request" => $row["request"],
|
||||
"action" => $row["action"],
|
||||
"target" => $row["target"],
|
||||
"extra" => $row["extra"]
|
||||
);
|
||||
} else {
|
||||
$this->result["route"] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Save extends RoutesAPI {
|
||||
|
||||
private array $routes;
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
'routes' => new Parameter('routes',Parameter::TYPE_ARRAY, false)
|
||||
));
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->validateRoutes()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
|
||||
// DELETE old rules
|
||||
$this->success = ($sql->truncate("Route")->execute() !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
// INSERT new routes
|
||||
if ($this->success) {
|
||||
$stmt = $sql->insert("Route", array("request", "action", "target", "extra", "active"));
|
||||
|
||||
foreach($this->routes as $route) {
|
||||
$stmt->addRow($route["request"], $route["action"], $route["target"], $route["extra"], $route["active"]);
|
||||
}
|
||||
$this->success = ($stmt->execute() !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function validateRoutes() {
|
||||
|
||||
$this->routes = array();
|
||||
$keys = array(
|
||||
"request" => Parameter::TYPE_STRING,
|
||||
"action" => Parameter::TYPE_STRING,
|
||||
"target" => Parameter::TYPE_STRING,
|
||||
"extra" => Parameter::TYPE_STRING,
|
||||
"active" => Parameter::TYPE_BOOLEAN
|
||||
);
|
||||
|
||||
$actions = array(
|
||||
"redirect_temporary", "redirect_permanently", "static", "dynamic"
|
||||
);
|
||||
|
||||
foreach($this->getParam("routes") as $index => $route) {
|
||||
foreach($keys as $key => $expectedType) {
|
||||
if (!array_key_exists($key, $route)) {
|
||||
return $this->createError("Route $index missing key: $key");
|
||||
}
|
||||
|
||||
$value = $route[$key];
|
||||
$type = Parameter::parseType($value);
|
||||
if ($type !== $expectedType) {
|
||||
$expectedTypeName = Parameter::names[$expectedType];
|
||||
$gotTypeName = Parameter::names[$type];
|
||||
return $this->createError("Route $index has invalid value for key: $key, expected: $expectedTypeName, got: $gotTypeName");
|
||||
}
|
||||
}
|
||||
|
||||
$action = $route["action"];
|
||||
if (!in_array($action, $actions)) {
|
||||
return $this->createError("Invalid action: $action");
|
||||
}
|
||||
|
||||
if(empty($route["request"])) {
|
||||
return $this->createError("Request cannot be empty.");
|
||||
}
|
||||
|
||||
if(empty($route["target"])) {
|
||||
return $this->createError("Target cannot be empty.");
|
||||
}
|
||||
|
||||
// add start- and end pattern for database queries
|
||||
$route["request"] = $this->formatRegex($route["request"], true);
|
||||
$this->routes[] = $route;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,58 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Api;
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
|
||||
class SendMail extends Request {
|
||||
|
||||
public function __construct($user, $externCall = false) {
|
||||
parent::__construct($user, $externCall, array(
|
||||
'from' => new Parameter('from', Parameter::TYPE_EMAIL),
|
||||
'to' => new Parameter('to', Parameter::TYPE_EMAIL),
|
||||
'subject' => new StringType('subject', -1),
|
||||
'body' => new StringType('body', -1),
|
||||
'fromName' => new StringType('fromName', -1, true, ''),
|
||||
'replyTo' => new Parameter('to', Parameter::TYPE_EMAIL, true, ''),
|
||||
));
|
||||
$this->isPublic = false;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$mailConfig = $this->user->getConfiguration()->getMail();
|
||||
$mail = new \External\PHPMailer\PHPMailer;
|
||||
$mail->IsSMTP();
|
||||
$mail->setFrom($this->getParam('from'), $this->getParam('fromName'));
|
||||
$mail->addAddress($this->getParam('to'));
|
||||
$mail->Subject = $this->getParam('subject');
|
||||
$mail->SMTPDebug = 0;
|
||||
$mail->Host = $mailConfig->getHost();
|
||||
$mail->Port = $mailConfig->getPort();
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = $mailConfig->getLogin();
|
||||
$mail->Password = $mailConfig->getPassword();
|
||||
$mail->SMTPSecure = 'tls';
|
||||
$mail->IsHTML(true);
|
||||
$mail->CharSet = 'UTF-8';
|
||||
$mail->Body = $this->getParam('body');
|
||||
|
||||
$replyTo = $this->getParam('replyTo');
|
||||
if(!is_null($replyTo) && !empty($replyTo)) {
|
||||
$mail->AddReplyTo($replyTo, $this->getParam('fromName'));
|
||||
}
|
||||
|
||||
$this->success = @$mail->Send();
|
||||
if (!$this->success) {
|
||||
$this->lastError = 'Error sending Mail: ' . $mail->ErrorInfo;
|
||||
error_log("sendMail() failed: " . $mail->ErrorInfo);
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
@ -1,83 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Api;
|
||||
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
use Driver\SQL\Condition\CondOr;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
|
||||
class SetLanguage extends Request {
|
||||
|
||||
private $language;
|
||||
|
||||
public function __construct($user, $externCall = false) {
|
||||
parent::__construct($user, $externCall, array(
|
||||
'langId' => new Parameter('langId', Parameter::TYPE_INT, true, NULL),
|
||||
'langCode' => new StringType('langCode', 5, true, NULL),
|
||||
));
|
||||
}
|
||||
|
||||
private function checkLanguage() {
|
||||
$langId = $this->getParam("langId");
|
||||
$langCode = $this->getParam("langCode");
|
||||
|
||||
if(is_null($langId) && is_null($langCode)) {
|
||||
return $this->createError(L("Either langId or langCode must be given"));
|
||||
}
|
||||
|
||||
$res = $this->user->getSQL()
|
||||
->select("uid", "code", "name")
|
||||
->from("Language")
|
||||
->where(new CondOr(new Compare("uid", $langId), new Compare("code", $langCode)))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $this->user->getSQL()->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
if(count($res) == 0) {
|
||||
return $this->createError(L("This Language does not exist"));
|
||||
} else {
|
||||
$row = $res[0];
|
||||
$this->language = \Objects\Language::newInstance($row['uid'], $row['code'], $row['name']);
|
||||
if(!$this->language) {
|
||||
return $this->createError(L("Error while loading language"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function updateLanguage() {
|
||||
$languageId = $this->language->getId();
|
||||
$userId = $this->user->getId();
|
||||
$sql = $this->user->getSQL();
|
||||
|
||||
$this->success = $sql->update("User")
|
||||
->set("language_id", $languageId)
|
||||
->where(new Compare("uid", $userId))
|
||||
->execute();
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!$this->checkLanguage())
|
||||
return false;
|
||||
|
||||
if($this->user->isLoggedIn()) {
|
||||
$this->updateLanguage();
|
||||
}
|
||||
|
||||
$this->user->setLangauge($this->language);
|
||||
return $this->success;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
169
core/Api/SettingsAPI.class.php
Normal file
169
core/Api/SettingsAPI.class.php
Normal file
@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace Api {
|
||||
|
||||
abstract class SettingsAPI extends Request {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Api\Settings {
|
||||
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
use Api\SettingsAPI;
|
||||
use Driver\SQL\Column\Column;
|
||||
use Driver\SQL\Condition\CondBool;
|
||||
use Driver\SQL\Condition\CondIn;
|
||||
use Driver\SQL\Condition\CondNot;
|
||||
use Driver\SQL\Condition\CondRegex;
|
||||
use Driver\SQL\Strategy\UpdateStrategy;
|
||||
use Objects\User;
|
||||
|
||||
class Get extends SettingsAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
'key' => new StringType('key', -1, true, NULL)
|
||||
));
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$key = $this->getParam("key");
|
||||
$sql = $this->user->getSQL();
|
||||
|
||||
$query = $sql->select("name", "value") ->from("Settings");
|
||||
|
||||
if (!is_null($key) && !empty($key)) {
|
||||
$query->where(new CondRegex(new Column("name"), $key));
|
||||
}
|
||||
|
||||
// filter sensitive values, if called from outside
|
||||
if ($this->isExternalCall()) {
|
||||
$query->where(new CondNot("private"));
|
||||
}
|
||||
|
||||
$res = $query->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$settings = array();
|
||||
foreach($res as $row) {
|
||||
$settings[$row["name"]] = $row["value"];
|
||||
}
|
||||
$this->result["settings"] = $settings;
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Set extends SettingsAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
'settings' => new Parameter('settings', Parameter::TYPE_ARRAY)
|
||||
));
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if (!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$values = $this->getParam("settings");
|
||||
if (empty($values)) {
|
||||
return $this->createError("No values given.");
|
||||
}
|
||||
|
||||
$paramKey = new StringType('key', 32);
|
||||
$paramValue = new StringType('value', 1024, true, NULL);
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$query = $sql->insert("Settings", array("name", "value"));
|
||||
$keys = array();
|
||||
$deleteKeys = array();
|
||||
|
||||
foreach($values as $key => $value) {
|
||||
if (!$paramKey->parseParam($key)) {
|
||||
$key = print_r($key, true);
|
||||
return $this->createError("Invalid Type for key in parameter settings: '$key' (Required: " . $paramKey->getTypeName() . ")");
|
||||
} else if(!is_null($value) && !$paramValue->parseParam($value)) {
|
||||
$value = print_r($value, true);
|
||||
return $this->createError("Invalid Type for value in parameter settings: '$value' (Required: " . $paramValue->getTypeName() . ")");
|
||||
} else if(preg_match("/^[a-zA-Z_][a-zA-Z_0-9-]*$/", $paramKey->value) !== 1) {
|
||||
return $this->createError("The property key should only contain alphanumeric characters, underscores and dashes");
|
||||
} else {
|
||||
if (!is_null($paramValue->value)) {
|
||||
$query->addRow($paramKey->value, $paramValue->value);
|
||||
} else {
|
||||
$deleteKeys[] = $paramKey->value;
|
||||
}
|
||||
$keys[] = $paramKey->value;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isExternalCall()) {
|
||||
$column = $this->checkReadonly($keys);
|
||||
if(!$this->success) {
|
||||
return false;
|
||||
} else if($column !== null) {
|
||||
return $this->createError("Column '$column' is readonly.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($deleteKeys) && !$this->deleteKeys($keys)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count($deleteKeys) !== count($keys)) {
|
||||
$query->onDuplicateKeyStrategy(new UpdateStrategy(
|
||||
array("name"),
|
||||
array("value" => new Column("value")))
|
||||
);
|
||||
|
||||
|
||||
$this->success = ($query->execute() !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function checkReadonly(array $keys) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("name")
|
||||
->from("Settings")
|
||||
->where(new CondBool("readonly"))
|
||||
->where(new CondIn("name", $keys))
|
||||
->limit(1)
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success && !empty($res)) {
|
||||
return $res[0]["name"];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function deleteKeys(array $keys) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->delete("Settings")
|
||||
->where(new CondIn("name", $keys))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
}
|
90
core/Api/Stats.class.php
Normal file
90
core/Api/Stats.class.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace Api;
|
||||
|
||||
use Driver\SQL\Condition\CondBool;
|
||||
|
||||
class Stats extends Request {
|
||||
|
||||
private bool $mailConfigured;
|
||||
private bool $recaptchaConfigured;
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array());
|
||||
}
|
||||
|
||||
private function getUserCount() {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->count())->from("User")->execute();
|
||||
$this->success = $this->success && ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
return ($this->success ? $res[0]["count"] : 0);
|
||||
}
|
||||
|
||||
private function getPageCount() {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->count())->from("Route")
|
||||
->where(new CondBool("active"))
|
||||
->execute();
|
||||
$this->success = $this->success && ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
return ($this->success ? $res[0]["count"] : 0);
|
||||
}
|
||||
|
||||
private function checkSettings() {
|
||||
$req = new \Api\Settings\Get($this->user);
|
||||
$this->success = $req->execute(array("key" => "^(mail_enabled|recaptcha_enabled)$"));
|
||||
$this->lastError = $req->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$settings = $req->getResult()["settings"];
|
||||
$this->mailConfigured = ($settings["mail_enabled"] ?? "0") === "1";
|
||||
$this->recaptchaConfigured = ($settings["recaptcha_enabled"] ?? "0") === "1";
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$userCount = $this->getUserCount();
|
||||
$pageCount = $this->getPageCount();
|
||||
$req = new \Api\Visitors\Stats($this->user);
|
||||
$this->success = $req->execute(array("type"=>"monthly"));
|
||||
$this->lastError = $req->getLastError();
|
||||
if (!$this->success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$visitorStatistics = $req->getResult()["visitors"];
|
||||
$loadAvg = "Unknown";
|
||||
if (function_exists("sys_getloadavg")) {
|
||||
$loadAvg = sys_getloadavg();
|
||||
}
|
||||
|
||||
if (!$this->checkSettings()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->result["userCount"] = $userCount;
|
||||
$this->result["pageCount"] = $pageCount;
|
||||
$this->result["visitors"] = $visitorStatistics;
|
||||
$this->result["server"] = array(
|
||||
"version" => WEBBASE_VERSION,
|
||||
"server" => $_SERVER["SERVER_SOFTWARE"] ?? "Unknown",
|
||||
"memory_usage" => memory_get_usage(),
|
||||
"load_avg" => $loadAvg,
|
||||
"database" => $this->user->getSQL()->getStatus(),
|
||||
"mail" => $this->mailConfigured,
|
||||
"reCaptcha" => $this->recaptchaConfigured
|
||||
);
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Api\User;
|
||||
|
||||
use \Api\Request;
|
||||
use \Api\Parameter\Parameter;
|
||||
use \Api\Parameter\StringType;
|
||||
use \Driver\SQL\Condition\Compare;
|
||||
|
||||
class Login extends Request {
|
||||
|
||||
private $startedAt;
|
||||
|
||||
public function __construct($user, $externCall = false) {
|
||||
parent::__construct($user, $externCall, array(
|
||||
'username' => new StringType('username', 32),
|
||||
'password' => new StringType('password'),
|
||||
'stayLoggedIn' => new Parameter('stayLoggedIn', Parameter::TYPE_BOOLEAN, true, true)
|
||||
));
|
||||
$this->forbidMethod("GET");
|
||||
}
|
||||
|
||||
private function wrongCredentials() {
|
||||
$runtime = microtime(true) - $this->startedAt;
|
||||
$sleepTime = round(3e6 - $runtime);
|
||||
if($sleepTime > 0) usleep($sleepTime);
|
||||
return $this->createError(L('Wrong username or password'));
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->user->isLoggedIn()) {
|
||||
$this->lastError = L('You are already logged in');
|
||||
$this->success = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->startedAt = microtime(true);
|
||||
$this->success = false;
|
||||
$username = $this->getParam('username');
|
||||
$password = $this->getParam('password');
|
||||
$stayLoggedIn = $this->getParam('stayLoggedIn');
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("User.uid", "User.password", "User.salt")
|
||||
->from("User")
|
||||
->where(new Compare("User.name", $username))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if($this->success) {
|
||||
if(count($res) === 0) {
|
||||
return $this->wrongCredentials();
|
||||
} else {
|
||||
$row = $res[0];
|
||||
$salt = $row['salt'];
|
||||
$uid = $row['uid'];
|
||||
$hash = hash('sha256', $password . $salt);
|
||||
if($hash === $row['password']) {
|
||||
if(!($this->success = $this->user->createSession($uid, $stayLoggedIn))) {
|
||||
return $this->createError("Error creating Session: " . $sql->getLastError());
|
||||
} else {
|
||||
$this->result['logoutIn'] = $this->user->getSession()->getExpiresSeconds();
|
||||
$this->success = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return $this->wrongCredentials();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Api\User;
|
||||
|
||||
use \Api\Request;
|
||||
|
||||
class Logout extends Request {
|
||||
|
||||
public function __construct($user, $externCall = false) {
|
||||
parent::__construct($user, $externCall);
|
||||
$this->loginRequired = true;
|
||||
$this->apiKeyAllowed = false;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->success = $this->user->logout();
|
||||
$this->lastError = $this->user->getSQL()->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
1140
core/Api/UserAPI.class.php
Normal file
1140
core/Api/UserAPI.class.php
Normal file
File diff suppressed because it is too large
Load Diff
67
core/Api/VerifyCaptcha.class.php
Normal file
67
core/Api/VerifyCaptcha.class.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Api;
|
||||
|
||||
use Api\Parameter\StringType;
|
||||
use Objects\User;
|
||||
|
||||
class VerifyCaptcha extends Request {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
"captcha" => new StringType("captcha"),
|
||||
"action" => new StringType("action"),
|
||||
));
|
||||
|
||||
$this->isPublic = false;
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if(!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$settings = $this->user->getConfiguration()->getSettings();
|
||||
if (!$settings->isRecaptchaEnabled()) {
|
||||
return $this->createError("Google reCaptcha is not enabled.");
|
||||
}
|
||||
|
||||
$url = "https://www.google.com/recaptcha/api/siteverify";
|
||||
$secret = $settings->getRecaptchaSecretKey();
|
||||
$captcha = $this->getParam("captcha");
|
||||
$action = $this->getParam("action");
|
||||
|
||||
$params = array(
|
||||
"secret" => $secret,
|
||||
"response" => $captcha
|
||||
);
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL,$url);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
$response = @json_decode(curl_exec($ch), true);
|
||||
curl_close ($ch);
|
||||
|
||||
$this->success = false;
|
||||
$this->lastError = "Could not verify captcha: No response from google received.";
|
||||
|
||||
if($response) {
|
||||
$this->success = $response["success"];
|
||||
if(!$this->success) {
|
||||
$this->lastError = "Could not verify captcha: " . implode(";", $response["error-codes"]);
|
||||
} else {
|
||||
$score = $response["score"];
|
||||
if($action !== $response["action"]) {
|
||||
$this->createError("Could not verify captcha: Action does not match");
|
||||
}
|
||||
else if($score < 0.7) {
|
||||
$this->createError("Could not verify captcha: Google ReCaptcha Score < 0.7 (Your score: $score), you are likely a bot");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
88
core/Api/VisitorsAPI.class.php
Normal file
88
core/Api/VisitorsAPI.class.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace Api {
|
||||
|
||||
abstract class VisitorsAPI extends Request {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace Api\Visitors {
|
||||
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
use Api\VisitorsAPI;
|
||||
use DateTime;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Driver\SQL\Query\Select;
|
||||
use Objects\User;
|
||||
|
||||
class Stats extends VisitorsAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
'type' => new StringType('type', 32),
|
||||
'date' => new Parameter('date', Parameter::TYPE_DATE, true, new DateTime())
|
||||
));
|
||||
}
|
||||
|
||||
private function setConditions(string $type, DateTime $date, Select $query) {
|
||||
if ($type === "yearly") {
|
||||
$yearStart = $date->format("Y0000");
|
||||
$yearEnd = $date->modify("+1 year")->format("Y0000");
|
||||
$query->where(new Compare("day", $yearStart, ">="));
|
||||
$query->where(new Compare("day", $yearEnd, "<"));
|
||||
} else if($type === "monthly") {
|
||||
$monthStart = $date->format("Ym00");
|
||||
$monthEnd = $date->modify("+1 month")->format("Ym00");
|
||||
$query->where(new Compare("day", $monthStart, ">="));
|
||||
$query->where(new Compare("day", $monthEnd, "<"));
|
||||
} else if($type === "weekly") {
|
||||
$weekStart = ($date->modify("monday this week"))->format("Ymd");
|
||||
$weekEnd = ($date->modify("sunday this week"))->format("Ymd");
|
||||
$query->where(new Compare("day", $weekStart, ">="));
|
||||
$query->where(new Compare("day", $weekEnd, "<="));
|
||||
} else {
|
||||
$this->createError("Invalid scope: $type");
|
||||
}
|
||||
}
|
||||
|
||||
public function execute($values = array()) {
|
||||
if (!parent::execute($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$date = $this->getParam("date");
|
||||
$type = $this->getParam("type");
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$query = $sql->select($sql->count(), "day")
|
||||
->from("Visitor")
|
||||
->where(new Compare("count", 1, ">"))
|
||||
->groupBy("day")
|
||||
->orderBy("day")
|
||||
->ascending();
|
||||
|
||||
$this->setConditions($type, $date, $query);
|
||||
if (!$this->success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$res = $query->execute();
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->result["type"] = $type;
|
||||
$this->result["visitors"] = array();
|
||||
|
||||
foreach($res as $row) {
|
||||
$day = DateTime::createFromFormat("Ymd", $row["day"])->format("Y/m/d");
|
||||
$count = $row["count"];
|
||||
$this->result["visitors"][$day] = $count;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
}
|
2
core/Configuration/.gitignore
vendored
2
core/Configuration/.gitignore
vendored
@ -1,3 +1 @@
|
||||
Mail\.class\.php
|
||||
JWT\.class\.php
|
||||
Database\.class\.php
|
||||
|
@ -2,53 +2,36 @@
|
||||
|
||||
namespace Configuration;
|
||||
|
||||
use Objects\ConnectionData;
|
||||
|
||||
class Configuration {
|
||||
|
||||
private $database;
|
||||
private $mail;
|
||||
private $jwt;
|
||||
private ?ConnectionData $database;
|
||||
private Settings $settings;
|
||||
|
||||
function __construct() {
|
||||
}
|
||||
$this->database = null;
|
||||
$this->settings = Settings::loadDefaults();
|
||||
|
||||
public function load() {
|
||||
try {
|
||||
|
||||
$classes = array(
|
||||
\Configuration\Database::class => &$this->database,
|
||||
\Configuration\Mail::class => &$this->mail,
|
||||
\Configuration\JWT::class => &$this->jwt
|
||||
);
|
||||
|
||||
$success = true;
|
||||
foreach($classes as $class => &$ref) {
|
||||
$path = getClassPath($class);
|
||||
if(!file_exists($path)) {
|
||||
$success = false;
|
||||
} else {
|
||||
include_once $path;
|
||||
if(class_exists($class)) {
|
||||
$ref = new $class();
|
||||
}
|
||||
}
|
||||
$class = \Configuration\Database::class;
|
||||
$path = getClassPath($class, true);
|
||||
if(file_exists($path) && is_readable($path)) {
|
||||
include_once $path;
|
||||
if(class_exists($class)) {
|
||||
$this->database = new \Configuration\Database();
|
||||
}
|
||||
|
||||
return $success;
|
||||
} catch(\Error $e) {
|
||||
die($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function getDatabase() { return $this->database; }
|
||||
public function getJWT() { return $this->jwt; }
|
||||
public function getMail() { return $this->mail; }
|
||||
|
||||
public function isFilePresent($className) {
|
||||
$path = getClassPath("\\Configuration\\$className");
|
||||
return file_exists($path);
|
||||
public function getDatabase() : ?ConnectionData {
|
||||
return $this->database;
|
||||
}
|
||||
|
||||
public function create($className, $data) {
|
||||
public function getSettings() : Settings {
|
||||
return $this->settings;
|
||||
}
|
||||
|
||||
public function create(string $className, $data) {
|
||||
$path = getClassPath("\\Configuration\\$className");
|
||||
|
||||
if($data) {
|
||||
@ -59,22 +42,15 @@ class Configuration {
|
||||
|
||||
namespace Configuration;
|
||||
|
||||
class $className {
|
||||
|
||||
private \$key;
|
||||
|
||||
class $className extends KeyData {
|
||||
|
||||
public function __construct() {
|
||||
\$this->key = '$key';
|
||||
parent::__construct('$key');
|
||||
}
|
||||
|
||||
public function getKey() {
|
||||
return \$this->key;
|
||||
}
|
||||
}
|
||||
|
||||
?>", false
|
||||
|
||||
}", false
|
||||
);
|
||||
} else {
|
||||
} else if($data instanceof ConnectionData) {
|
||||
$superClass = get_class($data);
|
||||
$host = addslashes($data->getHost());
|
||||
$port = intval($data->getPort());
|
||||
@ -98,22 +74,19 @@ class Configuration {
|
||||
public function __construct() {
|
||||
parent::__construct('$host', $port, '$login', '$password');$properties
|
||||
}
|
||||
}
|
||||
|
||||
?>", false
|
||||
}", false
|
||||
);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$code = intendCode(
|
||||
"<?php
|
||||
|
||||
?>", false);
|
||||
$code = "<?php";
|
||||
}
|
||||
|
||||
return @file_put_contents($path, $code);
|
||||
}
|
||||
|
||||
public function delete($className) {
|
||||
public function delete(string $className) {
|
||||
$path = getClassPath("\\Configuration\\$className");
|
||||
if(file_exists($path)) {
|
||||
return unlink($path);
|
||||
@ -121,6 +94,4 @@ class Configuration {
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
||||
}
|
@ -2,16 +2,16 @@
|
||||
|
||||
namespace Configuration;
|
||||
|
||||
use \Driver\SQL\Query\CreateTable;
|
||||
use \Driver\SQL\Query\Insert;
|
||||
use \Driver\SQL\Column\Column;
|
||||
use \Driver\SQL\Strategy\UpdateStrategy;
|
||||
use Driver\SQL\SQL;
|
||||
use \Driver\SQL\Strategy\SetNullStrategy;
|
||||
use \Driver\SQL\Strategy\CascadeStrategy;
|
||||
|
||||
class CreateDatabase {
|
||||
|
||||
public static function createQueries($sql) {
|
||||
// NOTE:
|
||||
// explicit serial ids removed due to postgres' serial implementation
|
||||
|
||||
public static function createQueries(SQL $sql) {
|
||||
$queries = array();
|
||||
|
||||
// Language
|
||||
@ -23,17 +23,18 @@ class CreateDatabase {
|
||||
->unique("code")
|
||||
->unique("name");
|
||||
|
||||
$queries[] = $sql->insert("Language", array("uid", "code", "name"))
|
||||
->addRow(1, "en_US", 'American English')
|
||||
->addRow(2, "de_DE", 'Deutsch Standard');
|
||||
$queries[] = $sql->insert("Language", array("code", "name"))
|
||||
->addRow( "en_US", 'American English')
|
||||
->addRow( "de_DE", 'Deutsch Standard');
|
||||
|
||||
$queries[] = $sql->createTable("User")
|
||||
->addSerial("uid")
|
||||
->addString("email", 64, true)
|
||||
->addString("name", 32)
|
||||
->addString("salt", 16)
|
||||
->addString("password", 64)
|
||||
->addString("password", 128)
|
||||
->addBool("confirmed", false)
|
||||
->addInt("language_id", true, 1)
|
||||
->addDateTime("registered_at", false, $sql->currentTimestamp())
|
||||
->primaryKey("uid")
|
||||
->unique("email")
|
||||
->unique("name")
|
||||
@ -49,35 +50,39 @@ class CreateDatabase {
|
||||
->addString("browser", 64)
|
||||
->addJson("data", false, '{}')
|
||||
->addBool("stay_logged_in", true)
|
||||
->addString("csrf_token", 16 )
|
||||
->primaryKey("uid", "user_id")
|
||||
->foreignKey("user_id", "User", "uid", new CascadeStrategy());
|
||||
|
||||
$queries[] = $sql->createTable("UserToken")
|
||||
->addInt("user_id")
|
||||
->addString("token", 36)
|
||||
->addEnum("token_type", array("password_reset", "confirmation"))
|
||||
->addEnum("token_type", array("password_reset", "email_confirm", "invite"))
|
||||
->addDateTime("valid_until")
|
||||
->addBool("used", false)
|
||||
->foreignKey("user_id", "User", "uid", new CascadeStrategy());
|
||||
|
||||
$queries[] = $sql->createTable("Group")
|
||||
->addSerial("uid")
|
||||
->addString("name", 32)
|
||||
->addString("color", 10)
|
||||
->primaryKey("uid")
|
||||
->unique("name");
|
||||
|
||||
$queries[] = $sql->insert("Group", array("uid", "name"))
|
||||
->addRow(USER_GROUP_DEFAULT, "Default")
|
||||
->addRow(USER_GROUP_ADMIN, "Administrator");
|
||||
$queries[] = $sql->insert("Group", array("name", "color"))
|
||||
->addRow(USER_GROUP_MODERATOR_NAME, "#007bff")
|
||||
->addRow(USER_GROUP_SUPPORT_NAME, "#28a745")
|
||||
->addRow(USER_GROUP_ADMIN_NAME, "#dc3545");
|
||||
|
||||
$queries[] = $sql->createTable("UserGroup")
|
||||
->addInt("user_id")
|
||||
->addInt("group_id")
|
||||
->unique("user_id", "group_id")
|
||||
->foreignKey("user_id", "User", "uid")
|
||||
->foreignKey("group_id", "Group", "uid");
|
||||
->foreignKey("user_id", "User", "uid", new CascadeStrategy())
|
||||
->foreignKey("group_id", "Group", "uid", new CascadeStrategy());
|
||||
|
||||
$queries[] = $sql->createTable("Notification")
|
||||
->addSerial("uid")
|
||||
->addEnum("type", array("default","message","warning"), false, "default")
|
||||
->addDateTime("created_at", false, $sql->currentTimestamp())
|
||||
->addString("title", 32)
|
||||
->addString("message", 256)
|
||||
@ -86,7 +91,7 @@ class CreateDatabase {
|
||||
$queries[] = $sql->createTable("UserNotification")
|
||||
->addInt("user_id")
|
||||
->addInt("notification_id")
|
||||
->addBool("seen")
|
||||
->addBool("seen", false)
|
||||
->foreignKey("user_id", "User", "uid")
|
||||
->foreignKey("notification_id", "Notification", "uid")
|
||||
->unique("user_id", "notification_id");
|
||||
@ -94,7 +99,7 @@ class CreateDatabase {
|
||||
$queries[] = $sql->createTable("GroupNotification")
|
||||
->addInt("group_id")
|
||||
->addInt("notification_id")
|
||||
->addBool("seen")
|
||||
->addBool("seen", false)
|
||||
->foreignKey("group_id", "Group", "uid")
|
||||
->foreignKey("notification_id", "Notification", "uid")
|
||||
->unique("group_id", "notification_id");
|
||||
@ -108,8 +113,116 @@ class CreateDatabase {
|
||||
->primaryKey("uid")
|
||||
->foreignKey("user_id", "User", "uid");
|
||||
|
||||
$queries[] = $sql->createTable("Visitor")
|
||||
->addInt("day")
|
||||
->addInt("count", false, 1)
|
||||
->addString("cookie", 26)
|
||||
->unique("day", "cookie");
|
||||
|
||||
$queries[] = $sql->createTable("Route")
|
||||
->addSerial("uid")
|
||||
->addString("request", 128)
|
||||
->addEnum("action", array("redirect_temporary", "redirect_permanently", "static", "dynamic"))
|
||||
->addString("target", 128)
|
||||
->addString("extra", 64, true)
|
||||
->addBool("active", true)
|
||||
->primaryKey("uid");
|
||||
|
||||
$queries[] = $sql->insert("Route", array("request", "action", "target", "extra"))
|
||||
->addRow("^/admin(/.*)?$", "dynamic", "\\Documents\\Admin", NULL)
|
||||
->addRow("^/register(/)?$", "dynamic", "\\Documents\\Account", "\\Views\\Account\\Register")
|
||||
->addRow("^/confirmEmail(/)?$", "dynamic", "\\Documents\\Account", "\\Views\\Account\\ConfirmEmail")
|
||||
->addRow("^/acceptInvite(/)?$", "dynamic", "\\Documents\\Account", "\\Views\\Account\\AcceptInvite")
|
||||
->addRow("^/resetPassword(/)?$", "dynamic", "\\Documents\\Account", "\\Views\\Account\\ResetPassword")
|
||||
->addRow("^/$", "static", "/static/welcome.html", NULL);
|
||||
|
||||
$queries[] = $sql->createTable("Settings")
|
||||
->addString("name", 32)
|
||||
->addString("value", 1024, true)
|
||||
->addBool("private", false) // these values are not returned from '/api/settings/get', but can be changed
|
||||
->addBool("readonly", false) // these values are neither returned, nor can be changed from outside
|
||||
->primaryKey("name");
|
||||
|
||||
$settingsQuery = $sql->insert("Settings", array("name", "value", "private", "readonly"))
|
||||
// ->addRow("mail_enabled", "0") # this key will be set during installation
|
||||
->addRow("mail_host", "", false, false)
|
||||
->addRow("mail_port", "", false, false)
|
||||
->addRow("mail_username", "", false, false)
|
||||
->addRow("mail_password", "", true, false)
|
||||
->addRow("mail_from", "", false, false)
|
||||
->addRow("message_confirm_email", self::MessageConfirmEmail(), false, false)
|
||||
->addRow("message_accept_invite", self::MessageAcceptInvite(), false, false)
|
||||
->addRow("message_reset_password", self::MessageResetPassword(), false, false);
|
||||
|
||||
(Settings::loadDefaults())->addRows($settingsQuery);
|
||||
$queries[] = $settingsQuery;
|
||||
|
||||
$queries[] = $sql->createTable("ContactRequest")
|
||||
->addSerial("uid")
|
||||
->addString("from_name", 32)
|
||||
->addString("from_email", 64)
|
||||
->addString("message", 512)
|
||||
->addDateTime("created_at", false, $sql->currentTimestamp())
|
||||
->primaryKey("uid");
|
||||
|
||||
$queries[] = $sql->createTable("ApiPermission")
|
||||
->addString("method", 32)
|
||||
->addJson("groups", true, '[]')
|
||||
->addString("description", 128, false, "")
|
||||
->primaryKey("method");
|
||||
|
||||
$queries[] = $sql->insert("ApiPermission", array("method", "groups", "description"))
|
||||
->addRow("ApiKey/create", array(), "Allows users to create API-Keys for themselves")
|
||||
->addRow("ApiKey/fetch", array(), "Allows users to list their API-Keys")
|
||||
->addRow("ApiKey/refresh", array(), "Allows users to refresh their API-Keys")
|
||||
->addRow("ApiKey/revoke", array(), "Allows users to revoke their API-Keys")
|
||||
->addRow("Groups/fetch", array(USER_GROUP_SUPPORT, USER_GROUP_ADMIN), "Allows users to list all available groups")
|
||||
->addRow("Groups/create", array(USER_GROUP_ADMIN), "Allows users to create a new groups")
|
||||
->addRow("Groups/delete", array(USER_GROUP_ADMIN), "Allows users to delete a group")
|
||||
->addRow("Routes/fetch", array(USER_GROUP_ADMIN), "Allows users to list all configured routes")
|
||||
->addRow("Routes/save", array(USER_GROUP_ADMIN), "Allows users to create, delete and modify routes")
|
||||
->addRow("Mail/test", array(USER_GROUP_SUPPORT, USER_GROUP_ADMIN), "Allows users to send a test email to a given address")
|
||||
->addRow("Settings/get", array(USER_GROUP_ADMIN), "Allows users to fetch server settings")
|
||||
->addRow("Settings/set", array(USER_GROUP_ADMIN), "Allows users create, delete or modify server settings")
|
||||
->addRow("Stats", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT), "Allows users to fetch server stats")
|
||||
->addRow("User/create", array(USER_GROUP_ADMIN), "Allows users to create a new user, email address does not need to be confirmed")
|
||||
->addRow("User/fetch", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT), "Allows users to list all registered users")
|
||||
->addRow("User/get", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT), "Allows users to get information about a single user")
|
||||
->addRow("User/invite", array(USER_GROUP_ADMIN), "Allows users to create a new user and send them an invitation link")
|
||||
->addRow("User/edit", array(USER_GROUP_ADMIN), "Allows users to edit details and group memberships of any user")
|
||||
->addRow("User/delete", array(USER_GROUP_ADMIN), "Allows users to delete any other user")
|
||||
->addRow("Permission/fetch", array(USER_GROUP_ADMIN), "Allows users to list all API permissions")
|
||||
->addRow("Visitors/stats", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT), "Allows users to see visitor statistics");
|
||||
|
||||
return $queries;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
private static function MessageConfirmEmail() : string {
|
||||
return "Hello {{username}},<br>" .
|
||||
"You recently created an account on {{site_name}}. Please click on the following link to " .
|
||||
"confirm your email address and complete your registration. If you haven't registered an " .
|
||||
"account, you can simply ignore this email. The link is valid for the next 48 hours:<br><br> " .
|
||||
"<a href=\"{{link}}\">{{link}}</a><br><br> " .
|
||||
"Best Regards<br> " .
|
||||
"{{site_name}} Administration";
|
||||
}
|
||||
|
||||
private static function MessageAcceptInvite() : string {
|
||||
return "Hello {{username}},<br>" .
|
||||
"You were invited to create an account on {{site_name}}. Please click on the following link to " .
|
||||
"confirm your email address and complete your registration by choosing a new password. " .
|
||||
"If you want to decline the invitation, you can simply ignore this email. The link is valid for the next 7 days:<br><br>" .
|
||||
"<a href=\"{{link}}\">{{link}}</a><br><br>" .
|
||||
"Best Regards<br>" .
|
||||
"{{site_name}} Administration";
|
||||
}
|
||||
|
||||
private static function MessageResetPassword() : string {
|
||||
return "Hello {{username}},<br>" .
|
||||
"you requested a password reset on {{site_name}}. Please click on the following link to " .
|
||||
"choose a new password. If this request was not intended, you can simply ignore the email. The Link is valid for one hour:<br><br>" .
|
||||
"<a href=\"{{link}}\">{{link}}</a><br><br>" .
|
||||
"Best Regards<br>" .
|
||||
"{{site_name}} Administration";
|
||||
}
|
||||
}
|
||||
|
107
core/Configuration/Settings.class.php
Normal file
107
core/Configuration/Settings.class.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Do not change settings here, they are dynamically loaded from database.
|
||||
*/
|
||||
|
||||
namespace Configuration;
|
||||
|
||||
use Driver\SQL\Query\Insert;
|
||||
use Objects\User;
|
||||
|
||||
class Settings {
|
||||
|
||||
private string $siteName;
|
||||
private string $baseUrl;
|
||||
private string $jwtSecret;
|
||||
private bool $installationComplete;
|
||||
private bool $registrationAllowed;
|
||||
private bool $recaptchaEnabled;
|
||||
private string $recaptchaPublicKey;
|
||||
private string $recaptchaPrivateKey;
|
||||
|
||||
public function getJwtSecret(): string {
|
||||
return $this->jwtSecret;
|
||||
}
|
||||
|
||||
public function isInstalled() {
|
||||
return $this->installationComplete;
|
||||
}
|
||||
|
||||
public static function loadDefaults() : Settings {
|
||||
$hostname = $_SERVER["SERVER_NAME"];
|
||||
$protocol = getProtocol();
|
||||
$jwt = generateRandomString(32);
|
||||
|
||||
$settings = new Settings();
|
||||
$settings->siteName = "WebBase";
|
||||
$settings->baseUrl = "$protocol://$hostname";
|
||||
$settings->jwtSecret = $jwt;
|
||||
$settings->installationComplete = false;
|
||||
$settings->registrationAllowed = false;
|
||||
$settings->recaptchaPublicKey = "";
|
||||
$settings->recaptchaPrivateKey = "";
|
||||
$settings->recaptchaEnabled = false;
|
||||
return $settings;
|
||||
}
|
||||
|
||||
public function loadFromDatabase(User $user) {
|
||||
$req = new \Api\Settings\Get($user);
|
||||
$success = $req->execute();
|
||||
|
||||
if ($success) {
|
||||
$result = $req->getResult()["settings"];
|
||||
$this->siteName = $result["site_name"] ?? $this->siteName;
|
||||
$this->registrationAllowed = $result["user_registration_enabled"] ?? $this->registrationAllowed;
|
||||
$this->installationComplete = $result["installation_completed"] ?? $this->installationComplete;
|
||||
$this->jwtSecret = $result["jwt_secret"] ?? $this->jwtSecret;
|
||||
$this->recaptchaEnabled = $result["recaptcha_enabled"] ?? $this->recaptchaEnabled;
|
||||
$this->recaptchaPublicKey = $result["recaptcha_public_key"] ?? $this->recaptchaPublicKey;
|
||||
$this->recaptchaPrivateKey = $result["recaptcha_private_key"] ?? $this->recaptchaPrivateKey;
|
||||
|
||||
if (!isset($result["jwt_secret"])) {
|
||||
$req = new \Api\Settings\Set($user);
|
||||
$req->execute(array("settings" => array(
|
||||
"jwt_secret" => $this->jwtSecret
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addRows(Insert $query) {
|
||||
$query->addRow("site_name", $this->siteName, false, false)
|
||||
->addRow("base_url", $this->baseUrl, false, false)
|
||||
->addRow("user_registration_enabled", $this->registrationAllowed ? "1" : "0", false, false)
|
||||
->addRow("installation_completed", $this->installationComplete ? "1" : "0", true, true)
|
||||
->addRow("jwt_secret", $this->jwtSecret, true, true)
|
||||
->addRow("recaptcha_enabled", $this->recaptchaEnabled ? "1" : "0", false, false)
|
||||
->addRow("recaptcha_public_key", $this->recaptchaPublicKey, false, false)
|
||||
->addRow("recaptcha_private_key", $this->recaptchaPrivateKey, true, false);
|
||||
}
|
||||
|
||||
public function getSiteName() : string {
|
||||
return $this->siteName;
|
||||
}
|
||||
|
||||
public function getBaseUrl() : string {
|
||||
return $this->baseUrl;
|
||||
}
|
||||
|
||||
public function isRecaptchaEnabled() : bool {
|
||||
return $this->recaptchaEnabled;
|
||||
}
|
||||
|
||||
public function getRecaptchaSiteKey() : string {
|
||||
return $this->recaptchaPublicKey;
|
||||
}
|
||||
|
||||
public function getRecaptchaSecretKey() : string {
|
||||
return $this->recaptchaPrivateKey;
|
||||
}
|
||||
|
||||
public function isRegistrationAllowed() : bool {
|
||||
return $this->registrationAllowed;
|
||||
}
|
||||
}
|
72
core/Documents/Account.class.php
Normal file
72
core/Documents/Account.class.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Documents {
|
||||
|
||||
use Documents\Account\AccountBody;
|
||||
use Documents\Account\AccountHead;
|
||||
use Elements\Document;
|
||||
use Objects\User;
|
||||
|
||||
class Account extends Document {
|
||||
public function __construct(User $user, ?string $view) {
|
||||
parent::__construct($user, AccountHead::class, AccountBody::class, $view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Documents\Account {
|
||||
|
||||
use Elements\Head;
|
||||
use Elements\Script;
|
||||
use Elements\SimpleBody;
|
||||
|
||||
class AccountHead extends Head {
|
||||
|
||||
public function __construct($document) {
|
||||
parent::__construct($document);
|
||||
}
|
||||
|
||||
protected function initSources() {
|
||||
$this->loadJQuery();
|
||||
$this->addJS(Script::CORE);
|
||||
$this->addJS(Script::ACCOUNT);
|
||||
$this->loadBootstrap();
|
||||
$this->loadFontawesome();
|
||||
}
|
||||
|
||||
protected function initMetas() {
|
||||
return array(
|
||||
array('name' => 'viewport', 'content' => 'width=device-width, initial-scale=1.0'),
|
||||
array('name' => 'format-detection', 'content' => 'telephone=yes'),
|
||||
array('charset' => 'utf-8'),
|
||||
array("http-equiv" => 'expires', 'content' => '0'),
|
||||
array("name" => 'robots', 'content' => 'noarchive'),
|
||||
);
|
||||
}
|
||||
|
||||
protected function initRawFields() {
|
||||
return array();
|
||||
}
|
||||
|
||||
protected function initTitle() {
|
||||
return "Account";
|
||||
}
|
||||
}
|
||||
|
||||
class AccountBody extends SimpleBody {
|
||||
|
||||
public function __construct($document) {
|
||||
parent::__construct($document);
|
||||
}
|
||||
|
||||
protected function getContent() {
|
||||
|
||||
$view = $this->getDocument()->getView();
|
||||
if ($view === null) {
|
||||
return "The page you does not exist or is no longer valid. <a href='/'>Return to start page</a>";
|
||||
}
|
||||
|
||||
return $view->getCode();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Documents {
|
||||
class Admin extends \Elements\Document {
|
||||
public function __construct($user) {
|
||||
parent::__construct($user, Admin\Head::class, Admin\Body::class);
|
||||
|
||||
use Documents\Admin\AdminHead;
|
||||
use Elements\Document;
|
||||
use Objects\User;
|
||||
use Views\Admin\AdminDashboardBody;
|
||||
use Views\Admin\LoginBody;
|
||||
|
||||
class Admin extends Document {
|
||||
public function __construct(User $user, ?string $view = NULL) {
|
||||
$body = $user->isLoggedIn() ? AdminDashboardBody::class : LoginBody::class;
|
||||
parent::__construct($user, AdminHead::class, $body, $view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Documents\Admin {
|
||||
|
||||
class Head extends \Elements\Head {
|
||||
use Elements\Head;
|
||||
use Elements\Link;
|
||||
use Elements\Script;
|
||||
|
||||
class AdminHead extends Head {
|
||||
|
||||
public function __construct($document) {
|
||||
parent::__construct($document);
|
||||
}
|
||||
|
||||
protected function initSources() {
|
||||
$this->loadJQuery();
|
||||
$this->loadBootstrap();
|
||||
$this->loadFontawesome();
|
||||
$this->addJS(\Elements\Script::CORE);
|
||||
$this->addCSS(\Elements\Link::CORE);
|
||||
$this->addJS(\Elements\Script::ADMIN);
|
||||
$this->addCSS(\Elements\Link::ADMIN);
|
||||
}
|
||||
|
||||
protected function initMetas() {
|
||||
@ -44,26 +50,4 @@ namespace Documents\Admin {
|
||||
return "WebBase - Administration";
|
||||
}
|
||||
}
|
||||
|
||||
class Body extends \Elements\Body {
|
||||
|
||||
public function __construct($document) {
|
||||
parent::__construct($document);
|
||||
}
|
||||
|
||||
public function getCode() {
|
||||
$html = parent::getCode();
|
||||
|
||||
$document = $this->getDocument();
|
||||
if(!$document->getUser()->isLoggedIn()) {
|
||||
$html .= new \Views\Login($document);
|
||||
} else {
|
||||
$html .= new \Views\Admin($document);
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
@ -1,27 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Documents {
|
||||
class Document404 extends \Elements\Document {
|
||||
public function __construct($user) {
|
||||
parent::__construct($user, Document404\Head404::class, Document404\Body404::class);
|
||||
|
||||
use Documents\Document404\Body404;
|
||||
use Documents\Document404\Head404;
|
||||
use Elements\Document;
|
||||
|
||||
class Document404 extends Document {
|
||||
public function __construct($user, ?string $view = NULL) {
|
||||
parent::__construct($user, Head404::class, Body404::class, $view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Documents\Document404 {
|
||||
|
||||
class Head404 extends \Elements\Head {
|
||||
use Elements\Body;
|
||||
use Elements\Head;
|
||||
use Elements\SimpleBody;
|
||||
use Views\View404;
|
||||
|
||||
class Head404 extends Head {
|
||||
|
||||
public function __construct($document) {
|
||||
parent::__construct($document);
|
||||
}
|
||||
|
||||
protected function initSources() {
|
||||
// $this->loadJQuery();
|
||||
// $this->loadBootstrap();
|
||||
// $this->loadFontawesome();
|
||||
// $this->addJS(\Elements\Script::CORE);
|
||||
// $this->addCSS(\Elements\Link::CORE);
|
||||
}
|
||||
|
||||
protected function initMetas() {
|
||||
@ -43,18 +48,18 @@ namespace Documents\Document404 {
|
||||
}
|
||||
}
|
||||
|
||||
class Body404 extends \Elements\Body {
|
||||
class Body404 extends SimpleBody {
|
||||
|
||||
public function __construct($document) {
|
||||
parent::__construct($document);
|
||||
}
|
||||
|
||||
public function getCode() {
|
||||
$html = parent::getCode();
|
||||
$html .= "<b>404 Not Found</b>";
|
||||
return $html;
|
||||
public function loadView() {
|
||||
http_response_code(404);
|
||||
}
|
||||
|
||||
protected function getContent() {
|
||||
return $this->load(View404::class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -1,9 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Documents {
|
||||
class Install extends \Elements\Document {
|
||||
|
||||
use Documents\Install\InstallBody;
|
||||
use Documents\Install\InstallHead;
|
||||
use Elements\Document;
|
||||
|
||||
class Install extends Document {
|
||||
public function __construct($user) {
|
||||
parent::__construct($user, Install\Head::class, Install\Body::class);
|
||||
parent::__construct($user, InstallHead::class, InstallBody::class);
|
||||
$this->databaseRequired = false;
|
||||
}
|
||||
}
|
||||
@ -11,7 +16,17 @@ namespace Documents {
|
||||
|
||||
namespace Documents\Install {
|
||||
|
||||
class Head extends \Elements\Head {
|
||||
use Configuration\CreateDatabase;
|
||||
use Driver\SQL\SQL;
|
||||
use Elements\Body;
|
||||
use Elements\Head;
|
||||
use Elements\Link;
|
||||
use Elements\Script;
|
||||
use External\PHPMailer\Exception;
|
||||
use External\PHPMailer\PHPMailer;
|
||||
use Objects\ConnectionData;
|
||||
|
||||
class InstallHead extends Head {
|
||||
|
||||
public function __construct($document) {
|
||||
parent::__construct($document);
|
||||
@ -21,9 +36,9 @@ namespace Documents\Install {
|
||||
$this->loadJQuery();
|
||||
$this->loadBootstrap();
|
||||
$this->loadFontawesome();
|
||||
$this->addJS(\Elements\Script::CORE);
|
||||
$this->addCSS(\Elements\Link::CORE);
|
||||
$this->addJS(\Elements\Script::INSTALL);
|
||||
$this->addJS(Script::CORE);
|
||||
$this->addCSS(Link::CORE);
|
||||
$this->addJS(Script::INSTALL);
|
||||
}
|
||||
|
||||
protected function initMetas() {
|
||||
@ -46,27 +61,31 @@ namespace Documents\Install {
|
||||
|
||||
}
|
||||
|
||||
class Body extends \Elements\Body {
|
||||
class InstallBody extends Body {
|
||||
|
||||
// Status enum
|
||||
const NOT_STARTED = 0;
|
||||
const PENDING = 1;
|
||||
const SUCCESFULL = 2;
|
||||
const SUCCESSFUL = 2;
|
||||
const ERROR = 3;
|
||||
|
||||
// Step enum
|
||||
const CHECKING_REQUIRMENTS = 1;
|
||||
const CHECKING_REQUIREMENTS = 1;
|
||||
const DATABASE_CONFIGURATION = 2;
|
||||
const CREATE_USER = 3;
|
||||
const ADD_MAIL_SERVICE = 4;
|
||||
const FINISH_INSTALLATION = 5;
|
||||
|
||||
//
|
||||
private $errorString;
|
||||
private string $errorString;
|
||||
private int $currentStep;
|
||||
private array $steps;
|
||||
|
||||
function __construct($document) {
|
||||
parent::__construct($document);
|
||||
$this->errorString = "";
|
||||
$this->currentStep = InstallBody::CHECKING_REQUIREMENTS;
|
||||
$this->steps = array();
|
||||
}
|
||||
|
||||
private function getParameter($name) {
|
||||
@ -80,7 +99,7 @@ namespace Documents\Install {
|
||||
private function getCurrentStep() {
|
||||
|
||||
if(!$this->checkRequirements()["success"]) {
|
||||
return self::CHECKING_REQUIRMENTS;
|
||||
return self::CHECKING_REQUIREMENTS;
|
||||
}
|
||||
|
||||
$user = $this->getDocument()->getUser();
|
||||
@ -92,6 +111,10 @@ namespace Documents\Install {
|
||||
}
|
||||
|
||||
$sql = $user->getSQL();
|
||||
if(!$sql || !$sql->isConnected()) {
|
||||
return self::DATABASE_CONFIGURATION;
|
||||
}
|
||||
|
||||
$countKeyword = $sql->count();
|
||||
$res = $sql->select($countKeyword)->from("User")->execute();
|
||||
if ($res === FALSE) {
|
||||
@ -104,19 +127,28 @@ namespace Documents\Install {
|
||||
}
|
||||
}
|
||||
|
||||
if($step === self::ADD_MAIL_SERVICE && $config->isFilePresent("Mail")) {
|
||||
$step = self::FINISH_INSTALLATION;
|
||||
if(!$config->isFilePresent("JWT") && !$config->create("JWT", generateRandomString(32))) {
|
||||
$this->errorString = "Unable to create jwt file";
|
||||
} else {
|
||||
$req = new \Api\Notifications\Create($user);
|
||||
$success = $req->execute(array(
|
||||
"title" => "Welcome",
|
||||
"message" => "Your Web-base was successfully installed. Check out the admin dashboard. Have fun!",
|
||||
"groupId" => USER_GROUP_ADMIN)
|
||||
);
|
||||
if ($step === self::ADD_MAIL_SERVICE) {
|
||||
$req = new \Api\Settings\Get($user);
|
||||
$success = $req->execute(array("key" => "^mail_enabled$"));
|
||||
if (!$success) {
|
||||
$this->errorString = $req->getLastError();
|
||||
return self::DATABASE_CONFIGURATION;
|
||||
} else if (isset($req->getResult()["settings"]["mail_enabled"])) {
|
||||
$step = self::FINISH_INSTALLATION;
|
||||
|
||||
$req = new \Api\Settings\Set($user);
|
||||
$success = $req->execute(array("settings" => array("installation_completed" => "1")));
|
||||
if (!$success) {
|
||||
$this->errorString = $req->getLastError();
|
||||
} else {
|
||||
$req = new \Api\Notifications\Create($user);
|
||||
$req->execute(array(
|
||||
"title" => "Welcome",
|
||||
"message" => "Your Web-base was successfully installed. Check out the admin dashboard. Have fun!",
|
||||
"groupId" => USER_GROUP_ADMIN
|
||||
)
|
||||
);
|
||||
$this->errorString = $req->getLastError();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -145,8 +177,8 @@ namespace Documents\Install {
|
||||
}
|
||||
}
|
||||
|
||||
if(version_compare(PHP_VERSION, '7.1', '<')) {
|
||||
$failedRequirements[] = "PHP Version <b>>= 7.1</b> is required. Got: <b>" . PHP_VERSION . "</b>";
|
||||
if(version_compare(PHP_VERSION, '7.4', '<')) {
|
||||
$failedRequirements[] = "PHP Version <b>>= 7.4</b> is required. Got: <b>" . PHP_VERSION . "</b>";
|
||||
$success = false;
|
||||
}
|
||||
|
||||
@ -213,16 +245,16 @@ namespace Documents\Install {
|
||||
$msg = "Unsupported database type. Must be one of: " . implode(", ", $supportedTypes);
|
||||
$success = false;
|
||||
} else {
|
||||
$connectionData = new \Objects\ConnectionData($host, $port, $username, $password);
|
||||
$connectionData = new ConnectionData($host, $port, $username, $password);
|
||||
$connectionData->setProperty('database', $database);
|
||||
$connectionData->setProperty('encoding', $encoding);
|
||||
$connectionData->setProperty('type', $type);
|
||||
$sql = \Driver\SQL\SQL::createConnection($connectionData);
|
||||
$sql = SQL::createConnection($connectionData);
|
||||
$success = false;
|
||||
if(!($sql instanceof \Driver\SQL\SQL)) {
|
||||
$msg = "Error connecting to database: " . str($sql);
|
||||
if(is_string($sql)) {
|
||||
$msg = "Error connecting to database: $sql";
|
||||
} else if(!$sql->isConnected()) {
|
||||
if (!$sql->checkRequirements()["success"]) {
|
||||
if (!$sql->checkRequirements()) {
|
||||
$driverName = $sql->getDriverName();
|
||||
$installLink = "https://www.php.net/manual/en/$driverName.setup.php";
|
||||
$link = $this->createExternalLink($installLink);
|
||||
@ -234,7 +266,7 @@ namespace Documents\Install {
|
||||
|
||||
$msg = "";
|
||||
$success = true;
|
||||
$queries = \Configuration\CreateDatabase::createQueries($sql);
|
||||
$queries = CreateDatabase::createQueries($sql);
|
||||
foreach($queries as $query) {
|
||||
if (!($res = $query->execute())) {
|
||||
$msg = "Error creating tables: " . $sql->getLastError();
|
||||
@ -243,7 +275,8 @@ namespace Documents\Install {
|
||||
}
|
||||
}
|
||||
|
||||
if($success && !$this->getDocument()->getUser()->getConfiguration()->create("Database", $connectionData)) {
|
||||
$config = $this->getDocument()->getUser()->getConfiguration();
|
||||
if(!$config->create("Database", $connectionData)) {
|
||||
$success = false;
|
||||
$msg = "Unable to write file";
|
||||
}
|
||||
@ -269,8 +302,8 @@ namespace Documents\Install {
|
||||
$username = $this->getParameter("username");
|
||||
$password = $this->getParameter("password");
|
||||
$confirmPassword = $this->getParameter("confirmPassword");
|
||||
$email = $this->getParameter("email") ?? "";
|
||||
|
||||
$msg = $this->errorString;
|
||||
$success = true;
|
||||
$missingInputs = array();
|
||||
|
||||
@ -292,29 +325,23 @@ namespace Documents\Install {
|
||||
if(!$success) {
|
||||
$msg = "Please fill out the following inputs:<br>" .
|
||||
$this->createUnorderedList($missingInputs);
|
||||
} else if(strlen($username) < 5 || strlen($username) > 32) {
|
||||
$msg = "The username should be between 5 and 32 characters long";
|
||||
$success = false;
|
||||
} else if(strcmp($password, $confirmPassword) !== 0) {
|
||||
$msg = "The given passwords do not match";
|
||||
$success = false;
|
||||
} else if(strlen($password) < 6) {
|
||||
$msg = "The password should be at least 6 characters long";
|
||||
$success = false;
|
||||
} else {
|
||||
$salt = generateRandomString(16);
|
||||
$hash = hash('sha256', $password . $salt);
|
||||
$sql = $user->getSQL();
|
||||
$req = new \Api\User\Create($user);
|
||||
$success = $req->execute(array(
|
||||
'username' => $username,
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
'confirmPassword' => $confirmPassword,
|
||||
));
|
||||
|
||||
$success = $sql->insert("User", array("name", "salt", "password"))
|
||||
->addRow($username, $salt, $hash)
|
||||
->returning("uid")
|
||||
->execute()
|
||||
&& $sql->insert("UserGroup", array("group_id", "user_id"))
|
||||
->addRow(USER_GROUP_ADMIN, $sql->getLastInsertId())
|
||||
->execute();
|
||||
|
||||
$msg = $sql->getLastError();
|
||||
$msg = $req->getLastError();
|
||||
if ($success) {
|
||||
$success = $sql->insert("UserGroup", array("group_id", "user_id"))
|
||||
->addRow(USER_GROUP_ADMIN, $req->getResult()["userId"])
|
||||
->execute();
|
||||
$msg = $sql->getLastError();
|
||||
}
|
||||
}
|
||||
|
||||
return array("msg" => $msg, "success" => $success);
|
||||
@ -333,10 +360,9 @@ namespace Documents\Install {
|
||||
$success = true;
|
||||
$msg = $this->errorString;
|
||||
if($this->getParameter("skip") === "true") {
|
||||
if(!$user->getConfiguration()->create("Mail", null)) {
|
||||
$success = false;
|
||||
$msg = "Unable to create file";
|
||||
}
|
||||
$req = new \Api\Settings\Set($user);
|
||||
$success = $req->execute(array("settings" => array( "mail_enabled" => "0" )));
|
||||
$msg = $req->getLastError();
|
||||
} else {
|
||||
|
||||
$address = $this->getParameter("address");
|
||||
@ -375,7 +401,7 @@ namespace Documents\Install {
|
||||
} else {
|
||||
$success = false;
|
||||
|
||||
$mail = new \External\PHPMailer\PHPMailer(true);
|
||||
$mail = new PHPMailer(true);
|
||||
$mail->IsSMTP();
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = $username;
|
||||
@ -395,16 +421,20 @@ namespace Documents\Install {
|
||||
$msg = "";
|
||||
$mail->smtpClose();
|
||||
}
|
||||
} catch(\External\PHPMailer\Exception $error) {
|
||||
} catch(Exception $error) {
|
||||
$msg = "Could not connect to SMTP Server: " . $error->errorMessage();
|
||||
}
|
||||
|
||||
if($success) {
|
||||
$connectionData = new \Objects\ConnectionData($address, $port, $username, $password);
|
||||
if(!$user->getConfiguration()->create("Mail", $connectionData)) {
|
||||
$success = false;
|
||||
$msg = "Unable to create file";
|
||||
}
|
||||
$req = new \Api\Settings\Set($user);
|
||||
$success = $req->execute(array("settings" => array(
|
||||
"mail_enabled" => "1",
|
||||
"mail_host" => "$address",
|
||||
"mail_port" => "$port",
|
||||
"mail_username" => "$username",
|
||||
"mail_password" => "$password",
|
||||
)));
|
||||
$msg = $req->getLastError();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -416,7 +446,7 @@ namespace Documents\Install {
|
||||
|
||||
switch($this->currentStep) {
|
||||
|
||||
case self::CHECKING_REQUIRMENTS:
|
||||
case self::CHECKING_REQUIREMENTS:
|
||||
return $this->checkRequirements();
|
||||
|
||||
case self::DATABASE_CONFIGURATION:
|
||||
@ -446,26 +476,26 @@ namespace Documents\Install {
|
||||
|
||||
switch($status) {
|
||||
case self::PENDING:
|
||||
$statusIcon = '<i class="fas fa-spin fa-spinner"></i>';
|
||||
$statusIcon = $this->createIcon("spinner");
|
||||
$statusText = "Loading…";
|
||||
$statusColor = "muted";
|
||||
break;
|
||||
|
||||
case self::SUCCESFULL:
|
||||
$statusIcon = '<i class="fas fa-check-circle"></i>';
|
||||
$statusText = "Successfull";
|
||||
case self::SUCCESSFUL:
|
||||
$statusIcon = $this->createIcon("check-circle");
|
||||
$statusText = "Successful";
|
||||
$statusColor = "success";
|
||||
break;
|
||||
|
||||
case self::ERROR:
|
||||
$statusIcon = '<i class="fas fa-times-circle"></i>';
|
||||
$statusIcon = $this->createIcon("times-circle");
|
||||
$statusText = "Failed";
|
||||
$statusColor = "danger";
|
||||
break;
|
||||
|
||||
case self::NOT_STARTED:
|
||||
default:
|
||||
$statusIcon = '<i class="far fa-circle"></i>';
|
||||
$statusIcon = $this->createIcon("circle", "far");
|
||||
$statusText = "Pending";
|
||||
$statusColor = "muted";
|
||||
break;
|
||||
@ -552,7 +582,7 @@ namespace Documents\Install {
|
||||
private function createProgessMainview() {
|
||||
|
||||
$views = array(
|
||||
self::CHECKING_REQUIRMENTS => array(
|
||||
self::CHECKING_REQUIREMENTS => array(
|
||||
"title" => "Application Requirements",
|
||||
"progressText" => "Checking requirements, please wait a moment…"
|
||||
),
|
||||
@ -585,6 +615,7 @@ namespace Documents\Install {
|
||||
"title" => "Create a User",
|
||||
"form" => array(
|
||||
array("title" => "Username", "name" => "username", "type" => "text", "required" => true),
|
||||
array("title" => "Email", "name" => "email", "type" => "text"),
|
||||
array("title" => "Password", "name" => "password", "type" => "password", "required" => true),
|
||||
array("title" => "Confirm Password", "name" => "confirmPassword", "type" => "password", "required" => true),
|
||||
),
|
||||
@ -661,7 +692,7 @@ namespace Documents\Install {
|
||||
);
|
||||
|
||||
if($this->currentStep != self::FINISH_INSTALLATION) {
|
||||
if ($this->currentStep == self::CHECKING_REQUIRMENTS) {
|
||||
if ($this->currentStep == self::CHECKING_REQUIREMENTS) {
|
||||
$buttons[] = array("title" => "Retry", "type" => "success", "id" => "btnRetry", "float" => "right");
|
||||
} else {
|
||||
$buttons[] = array("title" => "Submit", "type" => "success", "id" => "btnSubmit", "float" => "right");
|
||||
@ -683,7 +714,7 @@ namespace Documents\Install {
|
||||
$id = $button["id"];
|
||||
$float = $button["float"];
|
||||
$disabled = (isset($button["disabled"]) && $button["disabled"]) ? " disabled" : "";
|
||||
$button = "<button type=\"button\" id=\"$id\" class=\"btn btn-$type margin-xs\"$disabled>$title</button>";
|
||||
$button = "<button type=\"button\" id=\"$id\" class=\"btn btn-$type m-1\"$disabled>$title</button>";
|
||||
|
||||
if($float === "left") {
|
||||
$buttonsLeft .= $button;
|
||||
@ -701,12 +732,11 @@ namespace Documents\Install {
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
function getCode() {
|
||||
$html = parent::getCode();
|
||||
|
||||
$this->steps = array(
|
||||
self::CHECKING_REQUIRMENTS => array(
|
||||
self::CHECKING_REQUIREMENTS => array(
|
||||
"title" => "Checking requirements",
|
||||
"status" => self::ERROR
|
||||
),
|
||||
@ -731,12 +761,12 @@ namespace Documents\Install {
|
||||
$this->currentStep = $this->getCurrentStep();
|
||||
|
||||
// set status
|
||||
for($step = self::CHECKING_REQUIRMENTS; $step < $this->currentStep; $step++) {
|
||||
$this->steps[$step]["status"] = self::SUCCESFULL;
|
||||
for($step = self::CHECKING_REQUIREMENTS; $step < $this->currentStep; $step++) {
|
||||
$this->steps[$step]["status"] = self::SUCCESSFUL;
|
||||
}
|
||||
|
||||
if($this->currentStep == self::FINISH_INSTALLATION) {
|
||||
$this->steps[$this->currentStep]["status"] = self::SUCCESFULL;
|
||||
$this->steps[$this->currentStep]["status"] = self::SUCCESSFUL;
|
||||
}
|
||||
|
||||
// POST
|
||||
@ -748,6 +778,7 @@ namespace Documents\Install {
|
||||
|
||||
$progressSidebar = $this->createProgressSidebar();
|
||||
$progressMainview = $this->createProgessMainview();
|
||||
|
||||
$errorStyle = ($this->errorString ? '' : ' style="display:none"');
|
||||
$errorClass = ($this->errorString ? ' alert-danger' : '');
|
||||
|
||||
@ -773,7 +804,7 @@ namespace Documents\Install {
|
||||
</div>
|
||||
<div class=\"col-md-8 order-md-1\">
|
||||
$progressMainview
|
||||
<div class=\"alert$errorClass margin-top-m\" id=\"status\"$errorStyle>$this->errorString</div>
|
||||
<div class=\"alert$errorClass mt-4\" id=\"status\"$errorStyle>$this->errorString</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -781,9 +812,5 @@ namespace Documents\Install {
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -9,5 +9,3 @@ class BoolColumn extends Column {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -4,8 +4,8 @@ namespace Driver\SQL\Column;
|
||||
|
||||
class Column {
|
||||
|
||||
private $name;
|
||||
private $nullable;
|
||||
private string $name;
|
||||
private bool $nullable;
|
||||
private $defaultValue;
|
||||
|
||||
public function __construct($name, $nullable = false, $defaultValue = NULL) {
|
||||
@ -18,6 +18,4 @@ class Column {
|
||||
public function notNull() { return !$this->nullable; }
|
||||
public function getDefaultValue() { return $this->defaultValue; }
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
@ -7,6 +7,4 @@ class DateTimeColumn extends Column {
|
||||
public function __construct($name, $nullable=false, $defaultValue=NULL) {
|
||||
parent::__construct($name, $nullable, $defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
@ -4,7 +4,7 @@ namespace Driver\SQL\Column;
|
||||
|
||||
class EnumColumn extends Column {
|
||||
|
||||
private $values;
|
||||
private array $values;
|
||||
|
||||
public function __construct($name, $values, $nullable=false, $defaultValue=NULL) {
|
||||
parent::__construct($name, $nullable, $defaultValue);
|
||||
@ -13,5 +13,3 @@ class EnumColumn extends Column {
|
||||
|
||||
public function getValues() { return $this->values; }
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -9,5 +9,3 @@ class IntColumn extends Column {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -8,6 +8,4 @@ class JsonColumn extends Column {
|
||||
parent::__construct($name, $nullable, $defaultValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
@ -8,6 +8,4 @@ class SerialColumn extends Column {
|
||||
parent::__construct($name, false, $defaultValue); # not nullable
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
@ -4,7 +4,7 @@ namespace Driver\SQL\Column;
|
||||
|
||||
class StringColumn extends Column {
|
||||
|
||||
private $maxSize;
|
||||
private ?int $maxSize;
|
||||
|
||||
public function __construct($name, $maxSize=null, $nullable=false, $defaultValue=null) {
|
||||
parent::__construct($name, $nullable, $defaultValue);
|
||||
@ -12,6 +12,4 @@ class StringColumn extends Column {
|
||||
}
|
||||
|
||||
public function getMaxSize() { return $this->maxSize; }
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
@ -4,6 +4,10 @@ namespace Driver\SQL\Condition;
|
||||
|
||||
class Compare extends Condition {
|
||||
|
||||
private string $operator;
|
||||
private string $column;
|
||||
private $value;
|
||||
|
||||
public function __construct($col, $val, $operator='=') {
|
||||
$this->operator = $operator;
|
||||
$this->column = $col;
|
||||
@ -14,6 +18,4 @@ class Compare extends Condition {
|
||||
public function getValue() { return $this->value; }
|
||||
public function getOperator() { return $this->operator; }
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
@ -4,13 +4,11 @@ namespace Driver\SQL\Condition;
|
||||
|
||||
class CondAnd extends Condition {
|
||||
|
||||
private $conditions;
|
||||
private array $conditions;
|
||||
|
||||
public function __construct(...$conditions) {
|
||||
$this->conditions = $conditions;
|
||||
}
|
||||
|
||||
public function getConditions() { return $this->conditions; }
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
@ -4,12 +4,12 @@ namespace Driver\SQL\Condition;
|
||||
|
||||
class CondBool extends Condition {
|
||||
|
||||
private $value;
|
||||
|
||||
public function __construct($val) {
|
||||
$this->value = $val;
|
||||
}
|
||||
|
||||
public function getValue() { return $this->value; }
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
17
core/Driver/SQL/Condition/CondIn.class.php
Normal file
17
core/Driver/SQL/Condition/CondIn.class.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Driver\SQL\Condition;
|
||||
|
||||
class CondIn extends Condition {
|
||||
|
||||
private string $column;
|
||||
private $expression;
|
||||
|
||||
public function __construct(string $column, $expression) {
|
||||
$this->column = $column;
|
||||
$this->expression = $expression;
|
||||
}
|
||||
|
||||
public function getColumn() { return $this->column; }
|
||||
public function getExpression() { return $this->expression; }
|
||||
}
|
20
core/Driver/SQL/Condition/CondKeyword.class.php
Normal file
20
core/Driver/SQL/Condition/CondKeyword.class.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Driver\SQL\Condition;
|
||||
|
||||
abstract class CondKeyword extends Condition {
|
||||
|
||||
private $leftExpression;
|
||||
private $rightExpression;
|
||||
private string $keyword;
|
||||
|
||||
public function __construct($keyword, $leftExpression, $rightExpression) {
|
||||
$this->leftExpression = $leftExpression;
|
||||
$this->rightExpression = $rightExpression;
|
||||
$this->keyword = $keyword;
|
||||
}
|
||||
|
||||
public function getLeftExp() { return $this->leftExpression; }
|
||||
public function getRightExp() { return $this->rightExpression; }
|
||||
public function getKeyword() { return $this->keyword; }
|
||||
}
|
10
core/Driver/SQL/Condition/CondLike.class.php
Normal file
10
core/Driver/SQL/Condition/CondLike.class.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Driver\SQL\Condition;
|
||||
|
||||
class CondLike extends CondKeyword {
|
||||
|
||||
public function __construct($leftExpression, $rightExpression) {
|
||||
parent::__construct("LIKE", $leftExpression, $rightExpression);
|
||||
}
|
||||
}
|
16
core/Driver/SQL/Condition/CondNot.class.php
Normal file
16
core/Driver/SQL/Condition/CondNot.class.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Driver\SQL\Condition;
|
||||
|
||||
class CondNot extends Condition {
|
||||
|
||||
private $expression; // string or condition
|
||||
|
||||
public function __construct($expression) {
|
||||
$this->expression = $expression;
|
||||
}
|
||||
|
||||
public function getExpression() {
|
||||
return $this->expression;
|
||||
}
|
||||
}
|
@ -4,13 +4,11 @@ namespace Driver\SQL\Condition;
|
||||
|
||||
class CondOr extends Condition {
|
||||
|
||||
private $conditions;
|
||||
private array $conditions;
|
||||
|
||||
public function __construct(...$conditions) {
|
||||
$this->conditions = $conditions;
|
||||
$this->conditions = (!empty($conditions) && is_array($conditions[0])) ? $conditions[0] : $conditions;
|
||||
}
|
||||
|
||||
public function getConditions() { return $this->conditions; }
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
11
core/Driver/SQL/Condition/CondRegex.class.php
Normal file
11
core/Driver/SQL/Condition/CondRegex.class.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Driver\SQL\Condition;
|
||||
|
||||
class CondRegex extends CondKeyword {
|
||||
|
||||
public function __construct($leftExpression, $rightExpression) {
|
||||
parent::__construct("REGEXP", $leftExpression, $rightExpression);
|
||||
}
|
||||
|
||||
}
|
@ -4,6 +4,4 @@ namespace Driver\SQL\Condition;
|
||||
|
||||
abstract class Condition {
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
@ -4,13 +4,11 @@ namespace Driver\SQL\Constraint;
|
||||
|
||||
abstract class Constraint {
|
||||
|
||||
private $columnName;
|
||||
private array $columnNames;
|
||||
|
||||
public function __construct($columnName) {
|
||||
$this->columnName = $columnName;
|
||||
public function __construct($columnNames) {
|
||||
$this->columnNames = (!is_array($columnNames) ? array($columnNames) : $columnNames);
|
||||
}
|
||||
|
||||
public function getColumnName() { return $this->columnName; }
|
||||
};
|
||||
|
||||
?>
|
||||
public function getColumnNames() { return $this->columnNames; }
|
||||
}
|
@ -2,11 +2,13 @@
|
||||
|
||||
namespace Driver\SQL\Constraint;
|
||||
|
||||
use Driver\SQL\Strategy\Strategy;
|
||||
|
||||
class ForeignKey extends Constraint {
|
||||
|
||||
private $referencedTable;
|
||||
private $referencedColumn;
|
||||
private $strategy;
|
||||
private string $referencedTable;
|
||||
private string $referencedColumn;
|
||||
private ?Strategy $strategy;
|
||||
|
||||
public function __construct($name, $refTable, $refColumn, $strategy = NULL) {
|
||||
parent::__construct($name);
|
||||
@ -18,6 +20,4 @@ class ForeignKey extends Constraint {
|
||||
public function getReferencedTable() { return $this->referencedTable; }
|
||||
public function getReferencedColumn() { return $this->referencedColumn; }
|
||||
public function onDelete() { return $this->strategy; }
|
||||
};
|
||||
|
||||
?>
|
||||
}
|
@ -8,6 +8,4 @@ class PrimaryKey extends Constraint {
|
||||
parent::__construct((!empty($names) && is_array($names[0])) ? $names[0] : $names);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
?>
|
||||
}
|
||||
|
@ -8,6 +8,4 @@ class Unique extends Constraint {
|
||||
parent::__construct((!empty($names) && is_array($names[0])) ? $names[0] : $names);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
?>
|
||||
}
|
13
core/Driver/SQL/Expression/Add.class.php
Normal file
13
core/Driver/SQL/Expression/Add.class.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Driver\SQL\Expression;
|
||||
|
||||
use Driver\SQL\Condition\Compare;
|
||||
|
||||
class Add extends Compare {
|
||||
|
||||
public function __construct($col, $val) {
|
||||
parent::__construct($col, $val, "+");
|
||||
}
|
||||
|
||||
}
|
@ -4,13 +4,13 @@ namespace Driver\SQL;
|
||||
|
||||
class Join {
|
||||
|
||||
private $type;
|
||||
private $table;
|
||||
private $columnA;
|
||||
private $columnB;
|
||||
private string $type;
|
||||
private string $table;
|
||||
private string $columnA;
|
||||
private string $columnB;
|
||||
|
||||
public function __construct($type, $table, $columnA, $columnB) {
|
||||
$this->tpye = $type;
|
||||
$this->type = $type;
|
||||
$this->table = $table;
|
||||
$this->columnA = $columnA;
|
||||
$this->columnB = $columnB;
|
||||
@ -21,6 +21,4 @@ class Join {
|
||||
public function getColumnA() { return $this->columnA; }
|
||||
public function getColumnB() { return $this->columnB; }
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
@ -4,7 +4,7 @@ namespace Driver\SQL;
|
||||
|
||||
class Keyword {
|
||||
|
||||
private $value;
|
||||
private string $value;
|
||||
|
||||
public function __construct($value) {
|
||||
$this->value = $value;
|
||||
@ -12,6 +12,4 @@ class Keyword {
|
||||
|
||||
public function getValue() { return $this->value; }
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
@ -13,9 +13,9 @@ use \Driver\SQL\Column\DateTimeColumn;
|
||||
use Driver\SQL\Column\BoolColumn;
|
||||
use Driver\SQL\Column\JsonColumn;
|
||||
|
||||
use \Driver\SQL\Strategy\CascadeStrategy;
|
||||
use \Driver\SQL\Strategy\SetDefaultStrategy;
|
||||
use \Driver\SQL\Strategy\SetNullStrategy;
|
||||
use Driver\SQL\Condition\CondRegex;
|
||||
use Driver\SQL\Expression\Add;
|
||||
use Driver\SQL\Strategy\Strategy;
|
||||
use \Driver\SQL\Strategy\UpdateStrategy;
|
||||
|
||||
class MySQL extends SQL {
|
||||
@ -32,7 +32,7 @@ class MySQL extends SQL {
|
||||
return 'mysqli';
|
||||
}
|
||||
|
||||
// Connection Managment
|
||||
// Connection Management
|
||||
public function connect() {
|
||||
|
||||
if(!is_null($this->connection)) {
|
||||
@ -47,7 +47,7 @@ class MySQL extends SQL {
|
||||
$this->connectionData->getPort()
|
||||
);
|
||||
|
||||
if (mysqli_connect_errno($this->connection)) {
|
||||
if (mysqli_connect_errno()) {
|
||||
$this->lastError = "Failed to connect to MySQL: " . mysqli_connect_error();
|
||||
$this->connection = NULL;
|
||||
return false;
|
||||
@ -63,6 +63,7 @@ class MySQL extends SQL {
|
||||
}
|
||||
|
||||
mysqli_close($this->connection);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getLastError() {
|
||||
@ -81,6 +82,8 @@ class MySQL extends SQL {
|
||||
switch($paramType) {
|
||||
case Parameter::TYPE_BOOLEAN:
|
||||
$value = $value ? 1 : 0;
|
||||
$sqlParams[0] .= 'i';
|
||||
break;
|
||||
case Parameter::TYPE_INT:
|
||||
$sqlParams[0] .= 'i';
|
||||
break;
|
||||
@ -99,6 +102,10 @@ class MySQL extends SQL {
|
||||
$value = $value->format('Y-m-d H:i:s');
|
||||
$sqlParams[0] .= 's';
|
||||
break;
|
||||
case Parameter::TYPE_ARRAY:
|
||||
$value = json_encode($value);
|
||||
$sqlParams[0] .= 's';
|
||||
break;
|
||||
case Parameter::TYPE_EMAIL:
|
||||
default:
|
||||
$sqlParams[0] .= 's';
|
||||
@ -161,64 +168,39 @@ class MySQL extends SQL {
|
||||
return ($success && $returnValues) ? $resultRows : $success;
|
||||
}
|
||||
|
||||
public function executeInsert($insert) {
|
||||
$tableName = $this->tableName($insert->getTableName());
|
||||
$columns = $insert->getColumns();
|
||||
$rows = $insert->getRows();
|
||||
$onDuplicateKey = $insert->onDuplicateKey() ?? "";
|
||||
protected function getOnDuplicateStrategy(?Strategy $strategy, &$params) {
|
||||
if (is_null($strategy)) {
|
||||
return "";
|
||||
} else if ($strategy instanceof UpdateStrategy) {
|
||||
$updateValues = array();
|
||||
foreach($strategy->getValues() as $key => $value) {
|
||||
$leftColumn = $this->columnName($key);
|
||||
if ($value instanceof Column) {
|
||||
$columnName = $this->columnName($value->getName());
|
||||
$updateValues[] = "$leftColumn=VALUES($columnName)";
|
||||
} else if($value instanceof Add) {
|
||||
$columnName = $this->columnName($value->getColumn());
|
||||
$operator = $value->getOperator();
|
||||
$value = $value->getValue();
|
||||
$updateValues[] = "$leftColumn=$columnName$operator" . $this->addValue($value, $params);
|
||||
} else {
|
||||
$updateValues[] = "$leftColumn=" . $this->addValue($value, $params);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($rows)) {
|
||||
$this->lastError = "No rows to insert given.";
|
||||
return " ON DUPLICATE KEY UPDATE " . implode(",", $updateValues);
|
||||
} else {
|
||||
$strategyClass = get_class($strategy);
|
||||
$this->lastError = "ON DUPLICATE Strategy $strategyClass is not supported yet.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_null($columns) || empty($columns)) {
|
||||
$columns = "";
|
||||
$numColumns = count($rows[0]);
|
||||
} else {
|
||||
$numColumns = count($columns);
|
||||
$columns = " (" . $this->columnName($columns) . ")";
|
||||
}
|
||||
|
||||
$numRows = count($rows);
|
||||
$parameters = array();
|
||||
$values = implode(",", array_fill(0, $numRows, "(" . implode(",", array_fill(0, $numColumns, "?")) . ")"));
|
||||
|
||||
foreach($rows as $row) {
|
||||
$parameters = array_merge($parameters, $row);
|
||||
}
|
||||
|
||||
if ($onDuplicateKey) {
|
||||
if ($onDuplicateKey instanceof UpdateStrategy) {
|
||||
$updateValues = array();
|
||||
foreach($onDuplicateKey->getValues() as $key => $value) {
|
||||
if ($value instanceof Column) {
|
||||
$columnName = $value->getName();
|
||||
$updateValues[] = "`$key`=`$columnName`";
|
||||
} else {
|
||||
$updateValues[] = "`$key`=" . $this->addValue($value, $parameters);
|
||||
}
|
||||
}
|
||||
|
||||
$onDuplicateKey = " ON DUPLICATE KEY UPDATE " . implode(",", $updateValues);
|
||||
} else {
|
||||
$strategy = get_class($onDuplicateKey);
|
||||
$this->lastError = "ON DUPLICATE Strategy $strategy is not supported yet.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$query = "INSERT INTO $tableName$columns VALUES$values$onDuplicateKey";
|
||||
$success = $this->execute($query, $parameters);
|
||||
|
||||
if($success) {
|
||||
$this->lastInsertId = mysqli_insert_id($this->connection);
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
public function getColumnDefinition($column) {
|
||||
protected function fetchReturning($res, string $returningCol) {
|
||||
$this->lastInsertId = mysqli_insert_id($this->connection);
|
||||
}
|
||||
|
||||
public function getColumnDefinition(Column $column) {
|
||||
$columnName = $this->columnName($column->getName());
|
||||
$defaultValue = $column->getDefaultValue();
|
||||
|
||||
@ -255,7 +237,7 @@ class MySQL extends SQL {
|
||||
|
||||
$notNull = $column->notNull() ? " NOT NULL" : "";
|
||||
if (!is_null($defaultValue) || !$column->notNull()) {
|
||||
$defaultValue = " DEFAULT " . $this->getValueDefinition($column->getDefaultValue());
|
||||
$defaultValue = " DEFAULT " . $this->getValueDefinition($defaultValue);
|
||||
} else {
|
||||
$defaultValue = "";
|
||||
}
|
||||
@ -323,4 +305,7 @@ class MySQL extends SQL {
|
||||
return new Keyword("NOW()");
|
||||
}
|
||||
|
||||
};
|
||||
public function getStatus() {
|
||||
return mysqli_stat($this->connection);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ namespace Driver\SQL;
|
||||
|
||||
use \Api\Parameter\Parameter;
|
||||
|
||||
use \Driver\SQL\Column\Column;
|
||||
use Driver\SQL\Column\Column;
|
||||
use \Driver\SQL\Column\IntColumn;
|
||||
use \Driver\SQL\Column\SerialColumn;
|
||||
use \Driver\SQL\Column\StringColumn;
|
||||
@ -13,10 +13,10 @@ use \Driver\SQL\Column\DateTimeColumn;
|
||||
use Driver\SQL\Column\BoolColumn;
|
||||
use Driver\SQL\Column\JsonColumn;
|
||||
|
||||
use \Driver\SQL\Strategy\CascadeStrategy;
|
||||
use \Driver\SQL\Strategy\SetDefaultStrategy;
|
||||
use \Driver\SQL\Strategy\SetNullStrategy;
|
||||
use \Driver\SQL\Strategy\UpdateStrategy;
|
||||
use Driver\SQL\Condition\CondRegex;
|
||||
use Driver\SQL\Expression\Add;
|
||||
use Driver\SQL\Strategy\Strategy;
|
||||
use Driver\SQL\Strategy\UpdateStrategy;
|
||||
|
||||
class PostgreSQL extends SQL {
|
||||
|
||||
@ -32,7 +32,7 @@ class PostgreSQL extends SQL {
|
||||
return 'pgsql';
|
||||
}
|
||||
|
||||
// Connection Managment
|
||||
// Connection Management
|
||||
public function connect() {
|
||||
if(!is_null($this->connection)) {
|
||||
return true;
|
||||
@ -68,13 +68,13 @@ class PostgreSQL extends SQL {
|
||||
if(is_null($this->connection))
|
||||
return;
|
||||
|
||||
pg_close($this->connection);
|
||||
@pg_close($this->connection);
|
||||
}
|
||||
|
||||
public function getLastError() {
|
||||
$lastError = parent::getLastError();
|
||||
if (empty($lastError)) {
|
||||
$lastError = pg_last_error($this->connection) . " " . pg_last_error($this->connection);
|
||||
$lastError = trim(pg_last_error($this->connection) . " " . pg_last_error($this->connection));
|
||||
}
|
||||
|
||||
return $lastError;
|
||||
@ -99,6 +99,9 @@ class PostgreSQL extends SQL {
|
||||
case Parameter::TYPE_DATE_TIME:
|
||||
$value = $value->format("Y-m-d H:i:s");
|
||||
break;
|
||||
case Parameter::TYPE_ARRAY:
|
||||
$value = json_encode($value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -131,76 +134,48 @@ class PostgreSQL extends SQL {
|
||||
}
|
||||
}
|
||||
|
||||
// Querybuilder
|
||||
public function executeInsert($insert) {
|
||||
protected function getOnDuplicateStrategy(?Strategy $strategy, &$params) {
|
||||
if (!is_null($strategy)) {
|
||||
if ($strategy instanceof UpdateStrategy) {
|
||||
$updateValues = array();
|
||||
foreach($strategy->getValues() as $key => $value) {
|
||||
$leftColumn = $this->columnName($key);
|
||||
if ($value instanceof Column) {
|
||||
$columnName = $this->columnName($value->getName());
|
||||
$updateValues[] = "$leftColumn=EXCLUDED.$columnName";
|
||||
} else if ($value instanceof Add) {
|
||||
$columnName = $this->columnName($value->getColumn());
|
||||
$operator = $value->getOperator();
|
||||
$value = $value->getValue();
|
||||
$updateValues[] = "$leftColumn=$columnName$operator" . $this->addValue($value, $params);
|
||||
} else {
|
||||
$updateValues[] = "$leftColumn=" . $this->addValue($value, $parameters);
|
||||
}
|
||||
}
|
||||
|
||||
$tableName = $this->tableName($insert->getTableName());
|
||||
$columns = $insert->getColumns();
|
||||
$rows = $insert->getRows();
|
||||
$onDuplicateKey = $insert->onDuplicateKey() ?? "";
|
||||
|
||||
if (empty($rows)) {
|
||||
$this->lastError = "No rows to insert given.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_null($columns) || empty($columns)) {
|
||||
$columnStr = "";
|
||||
} else {
|
||||
$columnStr = " (" . $this->columnName($columns) . ")";
|
||||
}
|
||||
|
||||
$numRows = count($rows);
|
||||
$parameters = array();
|
||||
|
||||
$values = array();
|
||||
foreach($rows as $row) {
|
||||
$rowPlaceHolder = array();
|
||||
foreach($row as $val) {
|
||||
$rowPlaceHolder[] = $this->addValue($val, $parameters);
|
||||
}
|
||||
|
||||
$values[] = "(" . implode(",", $rowPlaceHolder) . ")";
|
||||
}
|
||||
|
||||
$values = implode(",", $values);
|
||||
|
||||
if ($onDuplicateKey) {
|
||||
/*if ($onDuplicateKey instanceof UpdateStrategy) {
|
||||
$updateValues = array();
|
||||
foreach($onDuplicateKey->getValues() as $key => $value) {
|
||||
if ($value instanceof Column) {
|
||||
$columnName = $value->getName();
|
||||
$updateValues[] = "\"$key\"=\"$columnName\"";
|
||||
$conflictingColumns = $this->columnName($strategy->getConflictingColumns());
|
||||
$updateValues = implode(",", $updateValues);
|
||||
return " ON CONFLICT ($conflictingColumns) DO UPDATE SET $updateValues";
|
||||
} else {
|
||||
$updateValues[] = "\"$key\"=" . $this->addValue($value, $parameters);
|
||||
$strategyClass = get_class($strategy);
|
||||
$this->lastError = "ON DUPLICATE Strategy $strategyClass is not supported yet.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$onDuplicateKey = " ON CONFLICT DO UPDATE SET " . implode(",", $updateValues);
|
||||
} else*/ {
|
||||
$strategy = get_class($onDuplicateKey);
|
||||
$this->lastError = "ON DUPLICATE Strategy $strategy is not supported yet.";
|
||||
return false;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$returningCol = $insert->getReturning();
|
||||
$returning = $returningCol ? (" RETURNING " . $this->columnName($returningCol)) : "";
|
||||
protected function getReturning(?string $columns) {
|
||||
return $columns ? (" RETURNING " . $this->columnName($columns)) : "";
|
||||
}
|
||||
|
||||
$query = "INSERT INTO $tableName$columnStr VALUES$values$onDuplicateKey$returning";
|
||||
$res = $this->execute($query, $parameters, !empty($returning));
|
||||
$success = ($res !== FALSE);
|
||||
|
||||
if($success && !empty($returning)) {
|
||||
$this->lastInsertId = $res[0][$returningCol];
|
||||
}
|
||||
|
||||
return $success;
|
||||
protected function fetchReturning($res, string $returningCol) {
|
||||
$this->lastInsertId = $res[0][$returningCol];
|
||||
}
|
||||
|
||||
// UGLY but.. what should i do?
|
||||
private function createEnum($enumColumn) {
|
||||
private function createEnum(EnumColumn $enumColumn) {
|
||||
$typeName = $enumColumn->getName();
|
||||
if(!endsWith($typeName, "_type")) {
|
||||
$typeName = "${typeName}_type";
|
||||
@ -319,5 +294,27 @@ class PostgreSQL extends SQL {
|
||||
public function currentTimestamp() {
|
||||
return new Keyword("CURRENT_TIMESTAMP");
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
public function getStatus() {
|
||||
$version = pg_version($this->connection)["client"] ?? "??";
|
||||
$status = pg_connection_status($this->connection);
|
||||
static $statusTexts = array(
|
||||
PGSQL_CONNECTION_OK => "PGSQL_CONNECTION_OK",
|
||||
PGSQL_CONNECTION_BAD => "PGSQL_CONNECTION_BAD",
|
||||
);
|
||||
|
||||
return ($statusTexts[$status] ?? "Unknown") . " (v$version)";
|
||||
}
|
||||
|
||||
protected function buildCondition($condition, &$params) {
|
||||
if($condition instanceof CondRegex) {
|
||||
$left = $condition->getLeftExp();
|
||||
$right = $condition->getRightExp();
|
||||
$left = ($left instanceof Column) ? $this->columnName($left->getName()) : $this->addValue($left, $params);
|
||||
$right = ($right instanceof Column) ? $this->columnName($right->getName()) : $this->addValue($right, $params);
|
||||
return $left . " ~ " . $right;
|
||||
} else {
|
||||
return parent::buildCondition($condition, $params);
|
||||
}
|
||||
}
|
||||
}
|
@ -16,10 +16,10 @@ use Driver\SQL\Constraint\ForeignKey;
|
||||
|
||||
class CreateTable extends Query {
|
||||
|
||||
private $tableName;
|
||||
private $columns;
|
||||
private $constraints;
|
||||
private $ifNotExists;
|
||||
private string $tableName;
|
||||
private array $columns;
|
||||
private array $constraints;
|
||||
private bool $ifNotExists;
|
||||
|
||||
public function __construct($sql, $name) {
|
||||
parent::__construct($sql);
|
||||
@ -92,6 +92,4 @@ class CreateTable extends Query {
|
||||
public function getTableName() { return $this->tableName; }
|
||||
public function getColumns() { return $this->columns; }
|
||||
public function getConstraints() { return $this->constraints; }
|
||||
};
|
||||
|
||||
?>
|
||||
}
|
||||
|
@ -2,10 +2,12 @@
|
||||
|
||||
namespace Driver\SQL\Query;
|
||||
|
||||
use Driver\SQL\Condition\CondOr;
|
||||
|
||||
class Delete extends Query {
|
||||
|
||||
private $table;
|
||||
private $conditions;
|
||||
private string $table;
|
||||
private array $conditions;
|
||||
|
||||
public function __construct($sql, $table) {
|
||||
parent::__construct($sql);
|
||||
@ -14,7 +16,7 @@ class Delete extends Query {
|
||||
}
|
||||
|
||||
public function where(...$conditions) {
|
||||
$this->conditions = array_merge($this->conditions, $conditions);
|
||||
$this->conditions[] = (count($conditions) === 1 ? $conditions : new CondOr($conditions));
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -24,6 +26,4 @@ class Delete extends Query {
|
||||
|
||||
public function getTable() { return $this->table; }
|
||||
public function getConditions() { return $this->conditions; }
|
||||
};
|
||||
|
||||
?>
|
||||
}
|
||||
|
@ -2,13 +2,15 @@
|
||||
|
||||
namespace Driver\SQL\Query;
|
||||
|
||||
use Driver\SQL\Strategy\Strategy;
|
||||
|
||||
class Insert extends Query {
|
||||
|
||||
private $tableName;
|
||||
private $columns;
|
||||
private $rows;
|
||||
private $onDuplicateKey;
|
||||
private $returning;
|
||||
private string $tableName;
|
||||
private array $columns;
|
||||
private array $rows;
|
||||
private ?Strategy $onDuplicateKey;
|
||||
private ?string $returning;
|
||||
|
||||
public function __construct($sql, $name, $columns=array()) {
|
||||
parent::__construct($sql);
|
||||
@ -43,6 +45,4 @@ class Insert extends Query {
|
||||
public function getRows() { return $this->rows; }
|
||||
public function onDuplicateKey() { return $this->onDuplicateKey; }
|
||||
public function getReturning() { return $this->returning; }
|
||||
};
|
||||
|
||||
?>
|
||||
}
|
@ -2,16 +2,23 @@
|
||||
|
||||
namespace Driver\SQL\Query;
|
||||
|
||||
use Driver\SQL\SQL;
|
||||
|
||||
abstract class Query {
|
||||
|
||||
protected $sql;
|
||||
protected SQL $sql;
|
||||
public bool $dump;
|
||||
|
||||
public function __construct($sql) {
|
||||
$this->sql = $sql;
|
||||
$this->dump = false;
|
||||
}
|
||||
|
||||
public function dump() {
|
||||
$this->dump = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public abstract function execute();
|
||||
|
||||
};
|
||||
|
||||
?>
|
||||
}
|
@ -2,16 +2,20 @@
|
||||
|
||||
namespace Driver\SQL\Query;
|
||||
|
||||
use Driver\SQL\Condition\CondOr;
|
||||
use Driver\SQL\Join;
|
||||
|
||||
class Select extends Query {
|
||||
|
||||
private $columns;
|
||||
private $tables;
|
||||
private $conditions;
|
||||
private $joins;
|
||||
private $orderColumns;
|
||||
private $sortAscending;
|
||||
private $limit;
|
||||
private $offset;
|
||||
private array $columns;
|
||||
private array $tables;
|
||||
private array $conditions;
|
||||
private array $joins;
|
||||
private array $orderColumns;
|
||||
private array $groupColumns;
|
||||
private bool $sortAscending;
|
||||
private int $limit;
|
||||
private int $offset;
|
||||
|
||||
public function __construct($sql, ...$columns) {
|
||||
parent::__construct($sql);
|
||||
@ -20,6 +24,7 @@ class Select extends Query {
|
||||
$this->conditions = array();
|
||||
$this->joins = array();
|
||||
$this->orderColumns = array();
|
||||
$this->groupColumns = array();
|
||||
$this->limit = 0;
|
||||
$this->offset = 0;
|
||||
$this->sortAscending = true;
|
||||
@ -31,17 +36,22 @@ class Select extends Query {
|
||||
}
|
||||
|
||||
public function where(...$conditions) {
|
||||
$this->conditions = array_merge($this->conditions, $conditions);
|
||||
$this->conditions[] = (count($conditions) === 1 ? $conditions : new CondOr($conditions));
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function innerJoin($table, $columnA, $columnB) {
|
||||
$this->joins[] = new \Driver\SQL\Join("INNER", $table, $columnA, $columnB);
|
||||
$this->joins[] = new Join("INNER", $table, $columnA, $columnB);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function leftJoin($table, $columnA, $columnB) {
|
||||
$this->joins[] = new \Driver\SQL\Join("LEFT", $table, $columnA, $columnB);
|
||||
$this->joins[] = new Join("LEFT", $table, $columnA, $columnB);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function groupBy(...$columns) {
|
||||
$this->groupColumns = $columns;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -51,12 +61,12 @@ class Select extends Query {
|
||||
}
|
||||
|
||||
public function ascending() {
|
||||
$this->ascending = true;
|
||||
$this->sortAscending = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function descending() {
|
||||
$this->ascending = false;
|
||||
$this->sortAscending = false;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -78,11 +88,10 @@ class Select extends Query {
|
||||
public function getTables() { return $this->tables; }
|
||||
public function getConditions() { return $this->conditions; }
|
||||
public function getJoins() { return $this->joins; }
|
||||
public function isOrderedAscending() { return $this->ascending; }
|
||||
public function isOrderedAscending() { return $this->sortAscending; }
|
||||
public function getOrderBy() { return $this->orderColumns; }
|
||||
public function getLimit() { return $this->limit; }
|
||||
public function getOffset() { return $this->offset; }
|
||||
public function getGroupBy() { return $this->groupColumns; }
|
||||
|
||||
};
|
||||
|
||||
?>
|
||||
}
|
@ -4,7 +4,7 @@ namespace Driver\SQL\Query;
|
||||
|
||||
class Truncate extends Query {
|
||||
|
||||
private $tableName;
|
||||
private string $tableName;
|
||||
|
||||
public function __construct($sql, $name) {
|
||||
parent::__construct($sql);
|
||||
@ -15,7 +15,5 @@ class Truncate extends Query {
|
||||
return $this->sql->executeTruncate($this);
|
||||
}
|
||||
|
||||
public function getTableName() { return $this->tableName; }
|
||||
};
|
||||
|
||||
?>
|
||||
public function getTable() { return $this->tableName; }
|
||||
}
|
@ -2,11 +2,13 @@
|
||||
|
||||
namespace Driver\SQL\Query;
|
||||
|
||||
use Driver\SQL\Condition\CondOr;
|
||||
|
||||
class Update extends Query {
|
||||
|
||||
private $values;
|
||||
private $table;
|
||||
private $conditions;
|
||||
private array $values;
|
||||
private string $table;
|
||||
private array $conditions;
|
||||
|
||||
public function __construct($sql, $table) {
|
||||
parent::__construct($sql);
|
||||
@ -16,7 +18,7 @@ class Update extends Query {
|
||||
}
|
||||
|
||||
public function where(...$conditions) {
|
||||
$this->conditions = array_merge($this->conditions, $conditions);
|
||||
$this->conditions[] = (count($conditions) === 1 ? $conditions : new CondOr($conditions));
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -32,6 +34,4 @@ class Update extends Query {
|
||||
public function getTable() { return $this->table; }
|
||||
public function getConditions() { return $this->conditions; }
|
||||
public function getValues() { return $this->values; }
|
||||
};
|
||||
|
||||
?>
|
||||
}
|
@ -2,16 +2,37 @@
|
||||
|
||||
namespace Driver\SQL;
|
||||
|
||||
use Driver\SQL\Column\Column;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Driver\SQL\Condition\CondBool;
|
||||
use Driver\SQL\Condition\CondIn;
|
||||
use Driver\SQL\Condition\Condition;
|
||||
use Driver\SQL\Condition\CondKeyword;
|
||||
use Driver\SQL\Condition\CondNot;
|
||||
use Driver\SQL\Condition\CondOr;
|
||||
use Driver\SQL\Constraint\Constraint;
|
||||
use \Driver\SQL\Constraint\Unique;
|
||||
use \Driver\SQL\Constraint\PrimaryKey;
|
||||
use \Driver\SQL\Constraint\ForeignKey;
|
||||
use Driver\SQL\Query\CreateTable;
|
||||
use Driver\SQL\Query\Delete;
|
||||
use Driver\SQL\Query\Insert;
|
||||
use Driver\SQL\Query\Query;
|
||||
use Driver\SQL\Query\Select;
|
||||
use Driver\SQL\Query\Truncate;
|
||||
use Driver\SQL\Query\Update;
|
||||
use Driver\SQL\Strategy\CascadeStrategy;
|
||||
use Driver\SQL\Strategy\SetDefaultStrategy;
|
||||
use Driver\SQL\Strategy\SetNullStrategy;
|
||||
use Driver\SQL\Strategy\Strategy;
|
||||
use Objects\ConnectionData;
|
||||
|
||||
abstract class SQL {
|
||||
|
||||
protected $lastError;
|
||||
protected string $lastError;
|
||||
protected $connection;
|
||||
protected $connectionData;
|
||||
protected $lastInsertId;
|
||||
protected ConnectionData $connectionData;
|
||||
protected int $lastInsertId;
|
||||
|
||||
public function __construct($connectionData) {
|
||||
$this->connection = NULL;
|
||||
@ -29,27 +50,27 @@ abstract class SQL {
|
||||
}
|
||||
|
||||
public function createTable($tableName) {
|
||||
return new Query\CreateTable($this, $tableName);
|
||||
return new CreateTable($this, $tableName);
|
||||
}
|
||||
|
||||
public function insert($tableName, $columns=array()) {
|
||||
return new Query\Insert($this, $tableName, $columns);
|
||||
return new Insert($this, $tableName, $columns);
|
||||
}
|
||||
|
||||
public function select(...$columNames) {
|
||||
return new Query\Select($this, $columNames);
|
||||
return new Select($this, $columNames);
|
||||
}
|
||||
|
||||
public function truncate($table) {
|
||||
return new Query\Truncate($this, $table);
|
||||
return new Truncate($this, $table);
|
||||
}
|
||||
|
||||
public function delete($table) {
|
||||
return new Query\Delete($this, $table);
|
||||
return new Delete($this, $table);
|
||||
}
|
||||
|
||||
public function update($table) {
|
||||
return new Query\Update($this, $table);
|
||||
return new Update($this, $table);
|
||||
}
|
||||
|
||||
// ####################
|
||||
@ -65,7 +86,54 @@ abstract class SQL {
|
||||
public abstract function disconnect();
|
||||
|
||||
// Querybuilder
|
||||
public function executeCreateTable($createTable) {
|
||||
protected function buildQuery(Query $query, array &$params) {
|
||||
if ($query instanceof Select) {
|
||||
$select = $query;
|
||||
$columns = $this->columnName($select->getColumns());
|
||||
$tables = $select->getTables();
|
||||
|
||||
if (!$tables) {
|
||||
return $this->execute("SELECT $columns", $params, true);
|
||||
}
|
||||
|
||||
$tables = $this->tableName($tables);
|
||||
$where = $this->getWhereClause($select->getConditions(), $params);
|
||||
|
||||
$joinStr = "";
|
||||
$joins = $select->getJoins();
|
||||
if (!empty($joins)) {
|
||||
foreach($joins as $join) {
|
||||
$type = $join->getType();
|
||||
$joinTable = $this->tableName($join->getTable());
|
||||
$columnA = $this->columnName($join->getColumnA());
|
||||
$columnB = $this->columnName($join->getColumnB());
|
||||
$joinStr .= " $type JOIN $joinTable ON $columnA=$columnB";
|
||||
}
|
||||
}
|
||||
|
||||
$groupBy = "";
|
||||
$groupColumns = $select->getGroupBy();
|
||||
if (!empty($groupColumns)) {
|
||||
$groupBy = " GROUP BY " . $this->columnName($groupColumns);
|
||||
}
|
||||
|
||||
$orderBy = "";
|
||||
$orderColumns = $select->getOrderBy();
|
||||
if (!empty($orderColumns)) {
|
||||
$orderBy = " ORDER BY " . $this->columnName($orderColumns);
|
||||
$orderBy .= ($select->isOrderedAscending() ? " ASC" : " DESC");
|
||||
}
|
||||
|
||||
$limit = ($select->getLimit() > 0 ? (" LIMIT " . $select->getLimit()) : "");
|
||||
$offset = ($select->getOffset() > 0 ? (" OFFSET " . $select->getOffset()) : "");
|
||||
return "SELECT $columns FROM $tables$joinStr$where$groupBy$orderBy$limit$offset";
|
||||
} else {
|
||||
$this->lastError = "buildQuery() not implemented for type: " . get_class($query);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
public function executeCreateTable(CreateTable $createTable) {
|
||||
$tableName = $this->tableName($createTable->getTableName());
|
||||
$ifNotExists = $createTable->ifNotExists() ? " IF NOT EXISTS": "";
|
||||
|
||||
@ -89,73 +157,94 @@ abstract class SQL {
|
||||
return $this->execute($query);
|
||||
}
|
||||
|
||||
// TODO pull this function up
|
||||
public abstract function executeInsert($query);
|
||||
public function executeInsert(Insert $insert) {
|
||||
|
||||
public function executeSelect($select) {
|
||||
$tableName = $this->tableName($insert->getTableName());
|
||||
$columns = $insert->getColumns();
|
||||
$rows = $insert->getRows();
|
||||
|
||||
$columns = $this->columnName($select->getColumns());
|
||||
$tables = $select->getTables();
|
||||
$params = array();
|
||||
|
||||
if (!$tables) {
|
||||
return "SELECT $columns";
|
||||
if (empty($rows)) {
|
||||
$this->lastError = "No rows to insert given.";
|
||||
return false;
|
||||
}
|
||||
|
||||
$tables = $this->tableName($tables);
|
||||
$where = $this->getWhereClause($select->getConditions(), $params);
|
||||
if (is_null($columns) || empty($columns)) {
|
||||
$columnStr = "";
|
||||
} else {
|
||||
$columnStr = " (" . $this->columnName($columns) . ")";
|
||||
}
|
||||
|
||||
$joinStr = "";
|
||||
$joins = $select->getJoins();
|
||||
if (!empty($joins)) {
|
||||
foreach($joins as $join) {
|
||||
$type = $join->getType();
|
||||
$joinTable = $this->tableName($join->getTable());
|
||||
$columnA = $this->columnName($join->getColumnA());
|
||||
$columnB = $this->columnName($join->getColumnB());
|
||||
$joinStr .= " $type JOIN $joinTable ON $columnA=$columnB";
|
||||
$parameters = array();
|
||||
$values = array();
|
||||
foreach($rows as $row) {
|
||||
$rowPlaceHolder = array();
|
||||
foreach($row as $val) {
|
||||
$rowPlaceHolder[] = $this->addValue($val, $parameters);
|
||||
}
|
||||
|
||||
$values[] = "(" . implode(",", $rowPlaceHolder) . ")";
|
||||
}
|
||||
|
||||
$orderBy = "";
|
||||
$orderColumns = $select->getOrderBy();
|
||||
if (!empty($orderColumns)) {
|
||||
$orderBy = " ORDER BY " . $this->columnName($orderColumns);
|
||||
$orderBy .= ($select->isOrderedAscending() ? " ASC" : " DESC");
|
||||
$values = implode(",", $values);
|
||||
|
||||
$onDuplicateKey = $this->getOnDuplicateStrategy($insert->onDuplicateKey(), $parameters);
|
||||
if ($onDuplicateKey === FALSE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$limit = ($select->getLimit() > 0 ? (" LIMIT " . $select->getLimit()) : "");
|
||||
$offset = ($select->getOffset() > 0 ? (" OFFSET " . $select->getOffset()) : "");
|
||||
$query = "SELECT $columns FROM $tables$joinStr$where$orderBy$limit$offset";
|
||||
$returningCol = $insert->getReturning();
|
||||
$returning = $this->getReturning($returningCol);
|
||||
|
||||
$query = "INSERT INTO $tableName$columnStr VALUES $values$onDuplicateKey$returning";
|
||||
if($insert->dump) { var_dump($query); var_dump($parameters); }
|
||||
$res = $this->execute($query, $parameters, !empty($returning));
|
||||
$success = ($res !== FALSE);
|
||||
|
||||
if($success && $returningCol) {
|
||||
$this->fetchReturning($res, $returningCol);
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
public function executeSelect(Select $select) {
|
||||
$params = array();
|
||||
$query = $this->buildQuery($select, $params);
|
||||
if($select->dump) { var_dump($query); var_dump($params); }
|
||||
return $this->execute($query, $params, true);
|
||||
}
|
||||
|
||||
public function executeDelete($delete) {
|
||||
public function executeDelete(Delete $delete) {
|
||||
|
||||
$params = array();
|
||||
$table = $this->tableName($delete->getTable());
|
||||
$where = $this->getWhereClause($delete->getConditions(), $params);
|
||||
|
||||
$query = "DELETE FROM $table$where";
|
||||
if($delete->dump) { var_dump($query); }
|
||||
return $this->execute($query, $params);
|
||||
}
|
||||
|
||||
public function executeTruncate(Truncate $truncate) {
|
||||
$query = "TRUNCATE " . $this->tableName($truncate->getTable());
|
||||
if ($truncate->dump) { var_dump($query); }
|
||||
return $this->execute($query);
|
||||
}
|
||||
|
||||
public function executeTruncate($truncate) {
|
||||
return $this->execute("TRUNCATE " . $truncate->getTable());
|
||||
}
|
||||
|
||||
public function executeUpdate($update) {
|
||||
public function executeUpdate(Update $update) {
|
||||
|
||||
$params = array();
|
||||
$table = $this->tableName($update->getTable());
|
||||
|
||||
$valueStr = array();
|
||||
foreach($update->getValues() as $key => $val) {
|
||||
$valueStr[] = "$key=" . $this->addValue($val, $params);
|
||||
$valueStr[] = $this->columnName($key) . "=" . $this->addValue($val, $params);
|
||||
}
|
||||
$valueStr = implode(",", $valueStr);
|
||||
|
||||
$where = $this->getWhereClause($update->getConditions(), $params);
|
||||
$query = "UPDATE $table SET $valueStr$where";
|
||||
if($update->dump) { var_dump($query); var_dump($params); }
|
||||
return $this->execute($query, $params);
|
||||
}
|
||||
|
||||
@ -167,10 +256,8 @@ abstract class SQL {
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract function getColumnDefinition($column);
|
||||
|
||||
public function getConstraintDefinition($constraint) {
|
||||
$columnName = $this->columnName($constraint->getColumnName());
|
||||
public function getConstraintDefinition(Constraint $constraint) {
|
||||
$columnName = $this->columnName($constraint->getColumnNames());
|
||||
if ($constraint instanceof PrimaryKey) {
|
||||
return "PRIMARY KEY ($columnName)";
|
||||
} else if ($constraint instanceof Unique) {
|
||||
@ -190,10 +277,19 @@ abstract class SQL {
|
||||
|
||||
return $code;
|
||||
} else {
|
||||
$this->lastError = "Unsupported constraint type: " . get_class($strategy);
|
||||
$this->lastError = "Unsupported constraint type: " . get_class($constraint);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function getReturning(?string $columns) {
|
||||
return "";
|
||||
}
|
||||
|
||||
protected abstract function getColumnDefinition(Column $column);
|
||||
protected abstract function fetchReturning($res, string $returningCol);
|
||||
protected abstract function getOnDuplicateStrategy(?Strategy $strategy, &$params);
|
||||
|
||||
protected abstract function getValueDefinition($val);
|
||||
protected abstract function addValue($val, &$params);
|
||||
|
||||
@ -201,17 +297,25 @@ abstract class SQL {
|
||||
protected abstract function columnName($col);
|
||||
|
||||
// Special Keywords and functions
|
||||
public function now() { return $this->currentTimestamp(); }
|
||||
public abstract function currentTimestamp();
|
||||
|
||||
public function count($col = NULL) {
|
||||
if (is_null($col)) {
|
||||
return new Keyword("COUNT(*) AS count");
|
||||
} else {
|
||||
$countCol = strtolower(str_replace(".","_", $col)) . "_count";
|
||||
$col = $this->columnName($col);
|
||||
return new Keyword("COUNT($col) AS count");
|
||||
return new Keyword("COUNT($col) AS $countCol");
|
||||
}
|
||||
}
|
||||
|
||||
public function sum($col) {
|
||||
$sumCol = strtolower(str_replace(".","_", $col)) . "_sum";
|
||||
$col = $this->columnName($col);
|
||||
return new Keyword("SUM($col) AS $sumCol");
|
||||
}
|
||||
|
||||
public function distinct($col) {
|
||||
$col = $this->columnName($col);
|
||||
return new Keyword("DISTINCT($col)");
|
||||
@ -221,29 +325,67 @@ abstract class SQL {
|
||||
protected abstract function execute($query, $values=NULL, $returnValues=false);
|
||||
|
||||
protected function buildCondition($condition, &$params) {
|
||||
if ($condition instanceof \Driver\SQL\Condition\CondOr) {
|
||||
|
||||
if ($condition instanceof CondOr) {
|
||||
$conditions = array();
|
||||
foreach($condition->getConditions() as $cond) {
|
||||
$conditions[] = $this->buildCondition($cond, $params);
|
||||
}
|
||||
return "(" . implode(" OR ", $conditions) . ")";
|
||||
} else if ($condition instanceof \Driver\SQL\Condition\Compare) {
|
||||
} else if ($condition instanceof Compare) {
|
||||
$column = $this->columnName($condition->getColumn());
|
||||
$value = $condition->getValue();
|
||||
$operator = $condition->getOperator();
|
||||
return $column . $operator . $this->addValue($value, $params);
|
||||
} else if ($condition instanceof \Driver\SQL\Condition\CondBool) {
|
||||
} else if ($condition instanceof CondBool) {
|
||||
return $this->columnName($condition->getValue());
|
||||
} else if (is_array($condition)) {
|
||||
if (count($condition) == 1) {
|
||||
if (count($condition) === 1) {
|
||||
return $this->buildCondition($condition[0], $params);
|
||||
} else {
|
||||
$conditions = array();
|
||||
foreach($condition as $cond) {
|
||||
foreach ($condition as $cond) {
|
||||
$conditions[] = $this->buildCondition($cond, $params);
|
||||
}
|
||||
return implode(" AND ", $conditions);
|
||||
}
|
||||
} else if($condition instanceof CondIn) {
|
||||
|
||||
$expression = $condition->getExpression();
|
||||
if (is_array($expression)) {
|
||||
$values = array();
|
||||
foreach ($expression as $value) {
|
||||
$values[] = $this->addValue($value, $params);
|
||||
}
|
||||
|
||||
$values = implode(",", $values);
|
||||
} else if($expression instanceof Select) {
|
||||
$values = $this->buildQuery($expression, $params);
|
||||
} else {
|
||||
$this->lastError = "Unsupported in-expression value: " . get_class($condition);
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->columnName($condition->getColumn()) . " IN ($values)";
|
||||
} else if($condition instanceof CondKeyword) {
|
||||
$left = $condition->getLeftExp();
|
||||
$right = $condition->getRightExp();
|
||||
$keyword = $condition->getKeyword();
|
||||
$left = ($left instanceof Column) ? $this->columnName($left->getName()) : $this->addValue($left, $params);
|
||||
$right = ($right instanceof Column) ? $this->columnName($right->getName()) : $this->addValue($right, $params);
|
||||
return "$left $keyword $right ";
|
||||
} else if($condition instanceof CondNot) {
|
||||
$expression = $condition->getExpression();
|
||||
if ($expression instanceof Condition) {
|
||||
$expression = $this->buildCondition($expression, $params);
|
||||
} else {
|
||||
$expression = $this->columnName($expression);
|
||||
}
|
||||
|
||||
return "NOT $expression";
|
||||
} else {
|
||||
$this->lastError = "Unsupported condition type: " . get_class($condition);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -260,7 +402,7 @@ abstract class SQL {
|
||||
$this->connection = NULL;
|
||||
}
|
||||
|
||||
public static function createConnection($connectionData) {
|
||||
public static function createConnection(ConnectionData $connectionData) {
|
||||
$type = $connectionData->getProperty("type");
|
||||
if ($type === "mysql") {
|
||||
$sql = new MySQL($connectionData);
|
||||
@ -279,6 +421,10 @@ abstract class SQL {
|
||||
|
||||
return $sql;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
public abstract function getStatus();
|
||||
|
||||
public function parseBool($val) : bool {
|
||||
return in_array($val, array(true, 1, '1', 't', 'true', 'TRUE'), true);
|
||||
}
|
||||
}
|
@ -7,6 +7,4 @@ class CascadeStrategy extends Strategy {
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
?>
|
||||
}
|
@ -7,6 +7,4 @@ class SetDefaultStrategy extends Strategy {
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
?>
|
||||
}
|
@ -7,6 +7,4 @@ class SetNullStrategy extends Strategy {
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
?>
|
||||
}
|
@ -4,6 +4,4 @@ namespace Driver\SQL\Strategy;
|
||||
|
||||
abstract class Strategy {
|
||||
|
||||
};
|
||||
|
||||
?>
|
||||
}
|
@ -4,13 +4,17 @@ namespace Driver\SQL\Strategy;
|
||||
|
||||
class UpdateStrategy extends Strategy {
|
||||
|
||||
private $values;
|
||||
private array $values;
|
||||
private array $conflictingColumns;
|
||||
|
||||
public function __construct($values) {
|
||||
public function __construct(array $conflictingColumns, array $values) {
|
||||
$this->conflictingColumns = $conflictingColumns;
|
||||
$this->values = $values;
|
||||
}
|
||||
|
||||
public function getValues() { return $this->values; }
|
||||
};
|
||||
public function getConflictingColumns() {
|
||||
return $this->conflictingColumns;
|
||||
}
|
||||
|
||||
?>
|
||||
public function getValues() { return $this->values; }
|
||||
}
|
@ -2,9 +2,8 @@
|
||||
|
||||
namespace Elements;
|
||||
|
||||
abstract class Body extends \View {
|
||||
abstract class Body extends View {
|
||||
public function __construct($document) {
|
||||
parent::__construct($document);
|
||||
}
|
||||
};
|
||||
?>
|
||||
}
|
@ -2,18 +2,22 @@
|
||||
|
||||
namespace Elements;
|
||||
|
||||
use Objects\User;
|
||||
|
||||
abstract class Document {
|
||||
|
||||
protected $head;
|
||||
protected $body;
|
||||
protected $user;
|
||||
protected $databaseRequired;
|
||||
protected Head $head;
|
||||
protected Body $body;
|
||||
protected User $user;
|
||||
protected bool $databaseRequired;
|
||||
private ?string $activeView;
|
||||
|
||||
public function __construct($user, $headClass, $bodyClass) {
|
||||
public function __construct(User $user, $headClass, $bodyClass, ?string $view = NULL) {
|
||||
$this->head = new $headClass($this);
|
||||
$this->body = new $bodyClass($this);
|
||||
$this->user = $user;
|
||||
$this->databaseRequired = true;
|
||||
$this->activeView = $view;
|
||||
}
|
||||
|
||||
public function getHead() { return $this->head; }
|
||||
@ -21,36 +25,14 @@ abstract class Document {
|
||||
public function getSQL() { return $this->user->getSQL(); }
|
||||
public function getUser() { return $this->user; }
|
||||
|
||||
protected function sendHeaders() {
|
||||
header("X-Frame-Options: DENY");
|
||||
}
|
||||
public function getView() : ?View {
|
||||
|
||||
public static function createSearchableDocument($documentClass, $user) {
|
||||
return new $documentClass($user);
|
||||
}
|
||||
|
||||
public static function createDocument($class) {
|
||||
// TODO: check instance, configuration, ..
|
||||
|
||||
require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/sql.php';
|
||||
// require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/conf/config.php';
|
||||
// require_once realpath($_SERVER['DOCUMENT_ROOT']) . "/php/pages/$file.php";
|
||||
require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/api/objects/User.php';
|
||||
|
||||
$connectionData = getSqlData($database);
|
||||
$sql = connectSQL($connectionData);
|
||||
if(!$sql->isConnected()) {
|
||||
http_response_code(500);
|
||||
die('Internal Database error');
|
||||
$file = getClassPath($this->activeView);
|
||||
if(!file_exists($file) || !is_subclass_of($this->activeView, View::class)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$user = new CUser($sql);
|
||||
$document = new $class($user);
|
||||
$code = $document->getCode();
|
||||
|
||||
$document->sendHeaders();
|
||||
$user->sendCookies();
|
||||
die($code);
|
||||
return new $this->activeView($this);
|
||||
}
|
||||
|
||||
function getCode() {
|
||||
@ -66,15 +48,14 @@ abstract class Document {
|
||||
|
||||
$body = $this->body->getCode();
|
||||
$head = $this->head->getCode();
|
||||
$lang = $this->user->getLanguage()->getShortCode();
|
||||
|
||||
$html = "<!DOCTYPE html>";
|
||||
$html .= "<html>";
|
||||
$html .= "<html lang=\"$lang\">";
|
||||
$html .= $head;
|
||||
$html .= $body;
|
||||
$html .= "</html>";
|
||||
return $html;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
?>
|
||||
}
|
@ -2,19 +2,20 @@
|
||||
|
||||
namespace Elements;
|
||||
|
||||
abstract class Head extends \View {
|
||||
abstract class Head extends View {
|
||||
|
||||
protected $sources;
|
||||
protected $title;
|
||||
protected $metas;
|
||||
protected $rawFields;
|
||||
protected $keywords;
|
||||
protected $description;
|
||||
protected $baseUrl;
|
||||
protected array $sources;
|
||||
protected string $title;
|
||||
protected array $metas;
|
||||
protected array $rawFields;
|
||||
protected array $keywords;
|
||||
protected string $description;
|
||||
protected string $baseUrl;
|
||||
|
||||
function __construct($document) {
|
||||
parent::__construct($document);
|
||||
$this->sources = array();
|
||||
$this->searchable = false;
|
||||
$this->metas = $this->initMetas();
|
||||
$this->rawFields = $this->initRawFields();
|
||||
$this->title = $this->initTitle();
|
||||
@ -45,7 +46,7 @@ abstract class Head extends \View {
|
||||
public function addKeywords($keywords) { array_merge($this->keywords, $keywords); }
|
||||
public function getTitle() { return $this->title; }
|
||||
|
||||
public function addCSS($href, $type = Link::MIME_TEXT_CSS) { $this->sources[] = new Link("stylesheet", $href, $type); }
|
||||
public function addCSS($href, $type = Link::MIME_TEXT_CSS) { $this->sources[] = new Link(Link::STYLESHEET, $href, $type); }
|
||||
public function addStyle($style) { $this->sources[] = new Style($style); }
|
||||
public function addJS($url) { $this->sources[] = new Script(Script::MIME_TEXT_JAVASCRIPT, $url, ""); }
|
||||
public function addJSCode($code) { $this->sources[] = new Script(Script::MIME_TEXT_JAVASCRIPT, "", $code); }
|
||||
@ -54,19 +55,6 @@ abstract class Head extends \View {
|
||||
$this->addCSS(Link::FONTAWESOME);
|
||||
}
|
||||
|
||||
public function loadSyntaxHighlighting() {
|
||||
$this->addJS(Script::HIGHLIGHT);
|
||||
$this->addJSCode(Script::HIGHLIGHT_JS_LOADER);
|
||||
$this->addCSS(Link::HIGHLIGHT);
|
||||
$this->addCSS(Link::HIGHLIGHT_THEME);
|
||||
}
|
||||
|
||||
public function loadJQueryTerminal($unixFormatting = true) {
|
||||
$this->addJS(Script::JQUERY_TERMINAL);
|
||||
if($unixFormatting) $this->addJS(Script::JQUERY_TERMINAL_UNIX);
|
||||
$this->addCSS(Link::JQUERY_TERMINAL);
|
||||
}
|
||||
|
||||
public function loadGoogleRecaptcha($siteKey) {
|
||||
$this->addJS("https://www.google.com/recaptcha/api.js?render=$siteKey");
|
||||
}
|
||||
@ -80,11 +68,6 @@ abstract class Head extends \View {
|
||||
$this->addJS(Script::BOOTSTRAP);
|
||||
}
|
||||
|
||||
public function loadChartJS() {
|
||||
$this->addJS(Script::MOMENT);
|
||||
$this->addJS(Script::CHART);
|
||||
}
|
||||
|
||||
public function getCode() {
|
||||
$header = "<head>";
|
||||
|
||||
@ -123,4 +106,3 @@ abstract class Head extends \View {
|
||||
return $header;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@ -2,41 +2,28 @@
|
||||
|
||||
namespace Elements;
|
||||
|
||||
class Link extends Source {
|
||||
class Link extends StaticView {
|
||||
|
||||
const STYLESHEET = "stylesheet";
|
||||
const MIME_TEXT_CSS = "text/css";
|
||||
|
||||
const FONTAWESOME = '/css/fontawesome.min.css';
|
||||
// const JQUERY_UI = '/css/jquery-ui.css';
|
||||
// const JQUERY_TERMINAL = '/css/jquery.terminal.min.css';
|
||||
const BOOTSTRAP = '/css/bootstrap.min.css';
|
||||
// const BOOTSTRAP_THEME = '/css/bootstrap-theme.min.css';
|
||||
// const BOOTSTRAP_DATEPICKER_CSS = '/css/bootstrap-datepicker.standalone.min.css';
|
||||
// const BOOTSTRAP_DATEPICKER3_CSS = '/css/bootstrap-datepicker.standalone.min.css';
|
||||
// const HIGHLIGHT = '/css/highlight.css';
|
||||
// const HIGHLIGHT_THEME = '/css/theme.css';
|
||||
const CORE = "/css/style.css";
|
||||
const ADMIN = "/css/admin.css";
|
||||
// const HOME = "/css/home.css";
|
||||
// const REVEALJS = "/css/reveal.css";
|
||||
// const REVEALJS_THEME_MOON = "/css/reveal_moon.css";
|
||||
// const REVEALJS_THEME_BLACK = "/css/reveal_black.css";
|
||||
const FONTAWESOME = "/css/fontawesome.min.css";
|
||||
const BOOTSTRAP = "/css/bootstrap.min.css";
|
||||
const CORE = "/css/style.css";
|
||||
const ACCOUNT = "/css/account.css";
|
||||
|
||||
private $type;
|
||||
private $rel;
|
||||
private string $type;
|
||||
private string $rel;
|
||||
private string $href;
|
||||
|
||||
function __construct($rel, $href, $type = "") {
|
||||
parent::__construct('link', $href);
|
||||
$this->href = $href;
|
||||
$this->type = $type;
|
||||
$this->rel = $rel;
|
||||
}
|
||||
|
||||
function getCode() {
|
||||
$type = (empty($this->type) ? "" : " type=\"$this->type\"");
|
||||
$link = "<link rel=\"$this->rel\" href=\"$this->url\" $type/>";
|
||||
return $link;
|
||||
return "<link rel=\"$this->rel\" href=\"$this->href\"$type/>";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -2,52 +2,28 @@
|
||||
|
||||
namespace Elements;
|
||||
|
||||
class Script extends Source {
|
||||
class Script extends StaticView {
|
||||
|
||||
const MIME_TEXT_JAVASCRIPT = "text/javascript";
|
||||
|
||||
const CORE = "/js/script.js";
|
||||
// const HOME = "/js/home.js";
|
||||
const ADMIN = "/js/admin.js";
|
||||
// const SORTTABLE = "/js/sorttable.js";
|
||||
const JQUERY = "/js/jquery.min.js";
|
||||
// const JQUERY_UI = "/js/jquery-ui.js";
|
||||
// const JQUERY_MASKED_INPUT = "/js/jquery.maskedinput.min.js";
|
||||
// const JQUERY_CONTEXT_MENU = "/js/jquery.contextmenu.min.js";
|
||||
// const JQUERY_TERMINAL = "/js/jquery.terminal.min.js";
|
||||
// const JQUERY_TERMINAL_UNIX = "/js/unix_formatting.js";
|
||||
// const JSCOLOR = "/js/jscolor.min.js";
|
||||
// const SYNTAX_HIGHLIGHTER = "/js/syntaxhighlighter.js";
|
||||
// const HIGHLIGHT = "/js/highlight.pack.js";
|
||||
// const GOOGLE_CHARTS = "/js/loader.js";
|
||||
const BOOTSTRAP = "/js/bootstrap.min.js";
|
||||
// const BOOTSTRAP_DATEPICKER_JS = "/js/bootstrap-datepicker.min.js";
|
||||
// const POPPER = "/js/popper.min.js";
|
||||
// const JSMPEG = "/js/jsmpeg.min.js";
|
||||
// const MOMENT = "/js/moment.min.js";
|
||||
// const CHART = "/js/chart.js";
|
||||
// const REVEALJS = "/js/reveal.js";
|
||||
// const REVEALJS_PLUGIN_NOTES = "/js/reveal_notes.js";
|
||||
const INSTALL = "/js/install.js";
|
||||
const CORE = "/js/script.js";
|
||||
const JQUERY = "/js/jquery.min.js";
|
||||
const INSTALL = "/js/install.js";
|
||||
const BOOTSTRAP = "/js/bootstrap.bundle.min.js";
|
||||
const ACCOUNT = "/js/account.js";
|
||||
|
||||
const HIGHLIGHT_JS_LOADER = "\$(document).ready(function(){\$('code').each(function(i, block) { hljs.highlightBlock(block); }); })";
|
||||
|
||||
private $type;
|
||||
private $content;
|
||||
private string $type;
|
||||
private string $content;
|
||||
private string $src;
|
||||
|
||||
function __construct($type, $src, $content = "") {
|
||||
parent::__construct('script', $src);
|
||||
$this->src = $src;
|
||||
$this->type = $type;
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
function getCode() {
|
||||
$src = (empty($this->url) ? "" : " src=\"$this->url\"");
|
||||
$script = "<script type=\"$this->type\"$src>";
|
||||
$script .= $this->content;
|
||||
$script .= '</script>';
|
||||
return $script;
|
||||
$src = (empty($this->src) ? "" : " src=\"$this->src\"");
|
||||
return "<script type=\"$this->type\"$src>$this->content</script>";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
16
core/Elements/SimpleBody.class.php
Normal file
16
core/Elements/SimpleBody.class.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Elements;
|
||||
|
||||
abstract class SimpleBody extends Body {
|
||||
public function __construct($document) {
|
||||
parent::__construct($document);
|
||||
}
|
||||
|
||||
public function getCode() {
|
||||
$content = $this->getContent();
|
||||
return parent::getCode() . "<body>$content</body>";
|
||||
}
|
||||
|
||||
protected abstract function getContent();
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Elements;
|
||||
|
||||
class Source extends \View {
|
||||
|
||||
protected $sourceType;
|
||||
protected $url;
|
||||
|
||||
public function __construct($sourceType, $url) {
|
||||
$this->sourceType = $sourceType;
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
public function getCode() {
|
||||
return "<$sourceType />";
|
||||
}
|
||||
|
||||
public function getUrl() { return $this->url; }
|
||||
}
|
||||
|
||||
?>
|
13
core/Elements/StaticView.class.php
Normal file
13
core/Elements/StaticView.class.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Elements;
|
||||
|
||||
abstract class StaticView {
|
||||
|
||||
public abstract function getCode();
|
||||
|
||||
public function __toString() {
|
||||
return $this->getCode();
|
||||
}
|
||||
|
||||
}
|
@ -2,12 +2,11 @@
|
||||
|
||||
namespace Elements;
|
||||
|
||||
class Style extends Source {
|
||||
class Style extends StaticView {
|
||||
|
||||
private $style;
|
||||
private string $style;
|
||||
|
||||
function __construct($style) {
|
||||
parent::__construct('style', '');
|
||||
$this->style = $style;
|
||||
}
|
||||
|
||||
@ -15,5 +14,3 @@ class Style extends Source {
|
||||
return "<style>$this->style</style>";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
136
core/Elements/View.class.php
Normal file
136
core/Elements/View.class.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
namespace Elements;
|
||||
|
||||
use External\PHPMailer\Exception;
|
||||
|
||||
abstract class View extends StaticView {
|
||||
|
||||
private Document $document;
|
||||
private bool $loadView;
|
||||
protected bool $searchable;
|
||||
protected string $reference;
|
||||
protected string $title;
|
||||
protected array $langModules;
|
||||
|
||||
public function __construct(Document $document, $loadView = true) {
|
||||
$this->document = $document;
|
||||
$this->searchable = false;
|
||||
$this->reference = "";
|
||||
$this->title = "Untitled View";
|
||||
$this->langModules = array();
|
||||
$this->loadView = $loadView;
|
||||
}
|
||||
|
||||
public function getTitle() { return $this->title; }
|
||||
public function getDocument() { return $this->document; }
|
||||
public function isSearchable() { return $this->searchable; }
|
||||
public function getReference() { return $this->reference; }
|
||||
|
||||
protected function load(string $viewClass) : string {
|
||||
try {
|
||||
$reflectionClass = new \ReflectionClass($viewClass);
|
||||
if ($reflectionClass->isSubclassOf(View::class) && $reflectionClass->isInstantiable()) {
|
||||
$view = $reflectionClass->newInstanceArgs(array($this->getDocument()));
|
||||
$view->loadView();
|
||||
return $view;
|
||||
}
|
||||
} catch(\ReflectionException $e) {
|
||||
error_log($e->getMessage());
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private function loadLanguageModules() {
|
||||
$lang = $this->document->getUser()->getLanguage();
|
||||
foreach($this->langModules as $langModule) {
|
||||
$lang->loadModule($langModule);
|
||||
}
|
||||
}
|
||||
|
||||
// Virtual Methods
|
||||
public function loadView() { }
|
||||
|
||||
public function getCode() {
|
||||
|
||||
// Load translations
|
||||
$this->loadLanguageModules();
|
||||
|
||||
// Load Meta Data + Head (title, scripts, includes, ...)
|
||||
if($this->loadView) {
|
||||
$this->loadView();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
// UI Functions
|
||||
private function createList($items, $tag) {
|
||||
if(count($items) === 0)
|
||||
return "<$tag></$tag>";
|
||||
else
|
||||
return "<$tag><li>" . implode("</li><li>", $items) . "</li></$tag>";
|
||||
}
|
||||
|
||||
public function createOrderedList($items=array()) {
|
||||
return $this->createList($items, "ol");
|
||||
}
|
||||
|
||||
public function createUnorderedList($items=array()) {
|
||||
return $this->createList($items, "ul");
|
||||
}
|
||||
|
||||
protected function createLink($link, $title=null) {
|
||||
if(is_null($title)) $title=$link;
|
||||
return "<a href=\"$link\">$title</a>";
|
||||
}
|
||||
|
||||
protected function createExternalLink($link, $title=null) {
|
||||
if(is_null($title)) $title=$link;
|
||||
return "<a href=\"$link\" target=\"_blank\" class=\"external\">$title</a>";
|
||||
}
|
||||
|
||||
protected function createIcon($icon, $type = "fas", $classes = "") {
|
||||
$iconClass = "$type fa-$icon";
|
||||
|
||||
if($icon === "spinner" || $icon === "circle-notch")
|
||||
$iconClass .= " fa-spin";
|
||||
|
||||
if($classes)
|
||||
$iconClass .= " $classes";
|
||||
|
||||
return "<i class=\"$iconClass\" ></i>";
|
||||
}
|
||||
|
||||
protected function createErrorText($text, $id="", $hidden=false) {
|
||||
return $this->createStatusText("danger", $text, $id, $hidden);
|
||||
}
|
||||
|
||||
protected function createWarningText($text, $id="", $hidden=false) {
|
||||
return $this->createStatusText("warning", $text, $id, $hidden);
|
||||
}
|
||||
|
||||
protected function createSuccessText($text, $id="", $hidden=false) {
|
||||
return $this->createStatusText("success", $text, $id, $hidden);
|
||||
}
|
||||
|
||||
protected function createSecondaryText($text, $id="", $hidden=false) {
|
||||
return $this->createStatusText("secondary", $text, $id, $hidden);
|
||||
}
|
||||
|
||||
protected function createInfoText($text, $id="", $hidden=false) {
|
||||
return $this->createStatusText("info", $text, $id, $hidden);
|
||||
}
|
||||
|
||||
protected function createStatusText($type, $text, $id="", $hidden=false) {
|
||||
if(strlen($id) > 0) $id = " id=\"$id\"";
|
||||
$hidden = ($hidden?" hidden" : "");
|
||||
return "<div class=\"alert alert-$type$hidden\" role=\"alert\"$id>$text</div>";
|
||||
}
|
||||
|
||||
protected function createBadge($type, $text) {
|
||||
$text = htmlspecialchars($text);
|
||||
return "<span class=\"badge badge-$type\">$text</span>";
|
||||
}
|
||||
}
|
5702
core/External/phpQuery.php
vendored
5702
core/External/phpQuery.php
vendored
File diff suppressed because it is too large
Load Diff
@ -6,9 +6,6 @@ abstract class ApiObject implements \JsonSerializable {
|
||||
|
||||
public abstract function jsonSerialize();
|
||||
|
||||
public function __construct() { }
|
||||
public function __toString() { return json_encode($this); }
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -4,11 +4,11 @@ namespace Objects;
|
||||
|
||||
class ConnectionData {
|
||||
|
||||
private $host;
|
||||
private $port;
|
||||
private $login;
|
||||
private $password;
|
||||
private $properties;
|
||||
private string $host;
|
||||
private int $port;
|
||||
private string $login;
|
||||
private string $password;
|
||||
private array $properties;
|
||||
|
||||
public function __construct($host, $port, $login, $password) {
|
||||
$this->host = $host;
|
||||
@ -32,12 +32,11 @@ class ConnectionData {
|
||||
}
|
||||
|
||||
$this->properties[$key] = $val;
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getHost() { return $this->host; }
|
||||
public function getPort() { return $this->port; }
|
||||
public function getLogin() { return $this->login; }
|
||||
public function getPassword() { return $this->password; }
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
@ -2,16 +2,18 @@
|
||||
|
||||
namespace Objects {
|
||||
|
||||
class Language extends ApiObject {
|
||||
use Objects\lang\LanguageModule;
|
||||
|
||||
class Language extends ApiObject {
|
||||
|
||||
const LANG_CODE_PATTERN = "/^[a-zA-Z]+_[a-zA-Z]+$/";
|
||||
|
||||
private $languageId;
|
||||
private $langCode;
|
||||
private $langName;
|
||||
private $modules;
|
||||
private int $languageId;
|
||||
private string $langCode;
|
||||
private string $langName;
|
||||
private array $modules;
|
||||
|
||||
protected $entries;
|
||||
protected array $entries;
|
||||
|
||||
public function __construct($languageId, $langCode, $langName) {
|
||||
$this->languageId = $languageId;
|
||||
@ -29,7 +31,7 @@ namespace Objects {
|
||||
public function getEntries() { return $this->entries; }
|
||||
public function getModules() { return $this->modules; }
|
||||
|
||||
public function loadModule($module) {
|
||||
public function loadModule(LanguageModule $module) {
|
||||
if(!is_object($module))
|
||||
$module = new $module;
|
||||
|
||||
@ -100,7 +102,8 @@ namespace Objects {
|
||||
}
|
||||
|
||||
namespace {
|
||||
function L($key) {
|
||||
|
||||
function L($key) {
|
||||
if(!array_key_exists('LANGUAGE', $GLOBALS))
|
||||
return $key;
|
||||
|
||||
@ -132,4 +135,3 @@ namespace {
|
||||
return $LANGUAGE->getShortCode();
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@ -2,28 +2,34 @@
|
||||
|
||||
namespace Objects;
|
||||
|
||||
use DateTime;
|
||||
use \Driver\SQL\Condition\Compare;
|
||||
use Exception;
|
||||
use External\JWT;
|
||||
|
||||
class Session extends ApiObject {
|
||||
|
||||
const DURATION = 120;
|
||||
# in minutes
|
||||
const DURATION = 60*24;
|
||||
|
||||
private $sessionId;
|
||||
private $user;
|
||||
private $expires;
|
||||
private $ipAddress;
|
||||
private $os;
|
||||
private $browser;
|
||||
private $stayLoggedIn;
|
||||
private ?int $sessionId;
|
||||
private User $user;
|
||||
private int $expires;
|
||||
private string $ipAddress;
|
||||
private ?string $os;
|
||||
private ?string $browser;
|
||||
private bool $stayLoggedIn;
|
||||
private string $csrfToken;
|
||||
|
||||
public function __construct($user, $sessionId) {
|
||||
public function __construct(User $user, ?int $sessionId, ?string $csrfToken) {
|
||||
$this->user = $user;
|
||||
$this->sessionId = $sessionId;
|
||||
$this->stayLoggedIn = true;
|
||||
$this->csrfToken = $csrfToken ?? generateRandomString(16);
|
||||
}
|
||||
|
||||
public static function create($user, $stayLoggedIn) {
|
||||
$session = new Session($user, null);
|
||||
$session = new Session($user, null, null);
|
||||
if($session->insert($stayLoggedIn)) {
|
||||
return $session;
|
||||
}
|
||||
@ -38,7 +44,7 @@ class Session extends ApiObject {
|
||||
$userAgent = @get_browser($_SERVER['HTTP_USER_AGENT'], true);
|
||||
$this->os = $userAgent['platform'] ?? "Unknown";
|
||||
$this->browser = $userAgent['parent'] ?? "Unknown";
|
||||
} catch(\Exception $ex) {
|
||||
} catch(Exception $ex) {
|
||||
$this->os = "Unknown";
|
||||
$this->browser = "Unknown";
|
||||
}
|
||||
@ -56,13 +62,11 @@ class Session extends ApiObject {
|
||||
|
||||
public function sendCookie() {
|
||||
$this->updateMetaData();
|
||||
$jwt = $this->user->getConfiguration()->getJwt();
|
||||
if($jwt) {
|
||||
$token = array('userId' => $this->user->getId(), 'sessionId' => $this->sessionId);
|
||||
$sessionCookie = \External\JWT::encode($token, $jwt->getKey());
|
||||
$secure = strcmp(getProtocol(), "https") === 0;
|
||||
setcookie('session', $sessionCookie, $this->getExpiresTime(), "/", "", $secure);
|
||||
}
|
||||
$settings = $this->user->getConfiguration()->getSettings();
|
||||
$token = array('userId' => $this->user->getId(), 'sessionId' => $this->sessionId);
|
||||
$sessionCookie = JWT::encode($token, $settings->getJwtSecret());
|
||||
$secure = strcmp(getProtocol(), "https") === 0;
|
||||
setcookie('session', $sessionCookie, $this->getExpiresTime(), "/", "", $secure);
|
||||
}
|
||||
|
||||
public function getExpiresTime() {
|
||||
@ -81,6 +85,7 @@ class Session extends ApiObject {
|
||||
'ipAddress' => $this->ipAddress,
|
||||
'os' => $this->os,
|
||||
'browser' => $this->browser,
|
||||
'csrf_token' => $this->csrfToken
|
||||
);
|
||||
}
|
||||
|
||||
@ -88,19 +93,20 @@ class Session extends ApiObject {
|
||||
$this->updateMetaData();
|
||||
$sql = $this->user->getSQL();
|
||||
|
||||
$hours = Session::DURATION;
|
||||
$columns = array("expires", "user_id", "ipAddress", "os", "browser", "data", "stay_logged_in");
|
||||
$minutes = Session::DURATION;
|
||||
$columns = array("expires", "user_id", "ipAddress", "os", "browser", "data", "stay_logged_in", "csrf_token");
|
||||
|
||||
$success = $sql
|
||||
->insert("Session", $columns)
|
||||
->addRow(
|
||||
(new \DateTime)->modify("+$hours hour"),
|
||||
(new DateTime())->modify("+$minutes minute"),
|
||||
$this->user->getId(),
|
||||
$this->ipAddress,
|
||||
$this->os,
|
||||
$this->browser,
|
||||
json_encode($_SESSION),
|
||||
$stayLoggedIn)
|
||||
$stayLoggedIn,
|
||||
$this->csrfToken)
|
||||
->returning("uid")
|
||||
->execute();
|
||||
|
||||
@ -113,32 +119,31 @@ class Session extends ApiObject {
|
||||
}
|
||||
|
||||
public function destroy() {
|
||||
$success = $this->user->getSQL()->update("Session")
|
||||
return $this->user->getSQL()->update("Session")
|
||||
->set("active", false)
|
||||
->where(new Compare("Session.uid", $this->sessionId))
|
||||
->where(new Compare("Session.user_id", $this->user->getId()))
|
||||
->execute();
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
public function update() {
|
||||
$this->updateMetaData();
|
||||
$hours = Session::DURATION;
|
||||
$minutes = Session::DURATION;
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$success = $sql->update("Session")
|
||||
->set("Session.expires", (new \DateTime)->modify("+$hours hour"))
|
||||
return $sql->update("Session")
|
||||
->set("Session.expires", (new DateTime())->modify("+$minutes minute"))
|
||||
->set("Session.ipAddress", $this->ipAddress)
|
||||
->set("Session.os", $this->os)
|
||||
->set("Session.browser", $this->browser)
|
||||
->set("Session.data", json_encode($_SESSION))
|
||||
->set("Session.csrf_token", $this->csrfToken)
|
||||
->where(new Compare("Session.uid", $this->sessionId))
|
||||
->where(new Compare("Session.user_id", $this->user->getId()))
|
||||
->execute();
|
||||
}
|
||||
|
||||
return $success;
|
||||
public function getCsrfToken(): string {
|
||||
return $this->csrfToken;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user