mirror of
https://github.com/Karaka-Management/oms-OnlineResourceWatcher.git
synced 2026-02-09 21:08:41 +00:00
prepare install
This commit is contained in:
parent
9b12b8d643
commit
496b7160b6
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -10,3 +10,6 @@
|
|||
[submodule "app/web/cssOMS"]
|
||||
path = app/web/cssOMS
|
||||
url = https://github.com/Karaka-Management/cssOMS.git
|
||||
[submodule "app/web/jsOMS"]
|
||||
path = app/web/jsOMS
|
||||
url = https://github.com/Karaka-Management/jsOMS.git
|
||||
|
|
|
|||
|
|
@ -38,6 +38,17 @@ namespace Controller {
|
|||
printf("Version: 1.0.0\n");
|
||||
}
|
||||
|
||||
void notInstalled(int argc, char **argv)
|
||||
{
|
||||
printf("No config file available, is the application installed?\n");
|
||||
printf("If not, run the application with:\n");
|
||||
printf(" --install -t 1 or\n");
|
||||
printf(" --install -t 2\n");
|
||||
printf("where 1 = web installation and 2 = local installation.\n\n");
|
||||
printf("Usually, '-t 2' is necessary if you see this message since the web\n");
|
||||
printf("installation is performed in the web installer as described in the README.\n");
|
||||
}
|
||||
|
||||
void checkResources(int argc, char **argv)
|
||||
{
|
||||
unsigned long long resourceId = atoll(Utils::ArrayUtils::get_arg("-r", argv, argc));
|
||||
|
|
|
|||
|
|
@ -12,8 +12,13 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
|
||||
#include "cOMS/Utils/Parser/Json.h"
|
||||
#include "cOMS/Utils/ArrayUtils.h"
|
||||
#include "DataStorage/Database/Connection/ConnectionFactory.h"
|
||||
#include "DataStorage/Database/Connection/ConnectionAbstract.h"
|
||||
#include "DataStorage/Database/Connection/DbConnectionConfig.h"
|
||||
|
||||
#include "../Models/InstallType.h"
|
||||
|
||||
|
|
@ -21,26 +26,92 @@ namespace Controller {
|
|||
namespace InstallController {
|
||||
void installApplication(int argc, char **argv)
|
||||
{
|
||||
// @todo handle install
|
||||
// create config
|
||||
// check install type
|
||||
// web = copy config from web
|
||||
// local
|
||||
// create sqlite db
|
||||
// create config from template
|
||||
}
|
||||
|
||||
void install(Models::InstallType type = Models::InstallType::LOCAL)
|
||||
{
|
||||
if (type == Models::InstallType::LOCAL) {
|
||||
// create sqlite database
|
||||
Models::InstallType type = (Models::InstallType) atoi(Utils::ArrayUtils::get_arg("-t", argv, argc));
|
||||
|
||||
int status = 0;
|
||||
if (type == Models::InstallType::WEB) {
|
||||
status = installWeb();
|
||||
} else {
|
||||
|
||||
status = installLocal();
|
||||
}
|
||||
|
||||
// create config file
|
||||
nlohmann::json config;
|
||||
if (status == 0) {
|
||||
printf("Application successfully installed\n");
|
||||
} else {
|
||||
printf("Application installation failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
int installWeb()
|
||||
{
|
||||
// Create config by copying weg config (nothing else necessary)
|
||||
Utils::FileUtils::file_body config = Utils::FileUtils::read_file("../web/config.json");
|
||||
|
||||
FILE *fp = fopen("config.json", "w");
|
||||
if (fp == NULL || config.content == NULL) {
|
||||
if (config.content != NULL) {
|
||||
free(config.content);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
fwrite(config.content, sizeof(char), config.size, fp);
|
||||
fclose(fp);
|
||||
|
||||
free(config.content);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int installLocal()
|
||||
{
|
||||
// Create config by copying config template
|
||||
FILE *in = fopen("Install/config.json", "r");
|
||||
if (in == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
nlohmann::json config = nlohmann::json::parse(in);
|
||||
|
||||
std::string strJson = config.dump(4);
|
||||
|
||||
FILE *out = fopen("config.json", "w");
|
||||
if (out == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fwrite(strJson.c_str(), sizeof(char), strJson.size(), out);
|
||||
|
||||
fclose(in);
|
||||
fclose(out);
|
||||
|
||||
// Create sqlite database
|
||||
FILE *fp = fopen("db.sqlite", "w");
|
||||
if (fp == NULL) {
|
||||
return -2;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
DataStorage::Database::DbConnectionConfig dbdata;
|
||||
DataStorage::Database::ConnectionAbstract *db = DataStorage::Database::create_connection(dbdata);
|
||||
if (db == NULL) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
// DbSchema *schema = DbSchema::fromJson(jsonString);
|
||||
// QueryBuilder::createFromSchema(schema);
|
||||
// QueryBuilder query = QueryBuilder(db, false);
|
||||
// query.createTable()
|
||||
// .field()
|
||||
// .field()
|
||||
// query->execute();
|
||||
|
||||
DataStorage::Database::close(db, dbdata);
|
||||
free(db);
|
||||
DataStorage::Database::free_DbConnectionConfig(&dbdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void parseConfigFile()
|
||||
|
|
|
|||
3
app/server/Install/config.json
Normal file
3
app/server/Install/config.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ namespace Models {
|
|||
} Account;
|
||||
|
||||
inline
|
||||
void freeAccount(Account *obj)
|
||||
void free_Account(Account *obj)
|
||||
{
|
||||
if (obj->email != NULL) {
|
||||
free(obj->email);
|
||||
|
|
@ -47,12 +47,11 @@ namespace Models {
|
|||
}
|
||||
|
||||
if (obj->org != NULL) {
|
||||
freeOrganization(obj->org);
|
||||
free_Organization(obj->org);
|
||||
free(obj->org);
|
||||
|
||||
obj->org = NULL;
|
||||
|
||||
}
|
||||
|
||||
free(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
namespace Models {
|
||||
typedef enum {
|
||||
WEB = 0,
|
||||
LOCAL = 1
|
||||
WEB = 1,
|
||||
LOCAL = 2
|
||||
} InstallType;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,9 +21,8 @@ namespace Models {
|
|||
} Organization;
|
||||
|
||||
inline
|
||||
void freeOrganization(Organization *obj)
|
||||
void free_Organization(Organization *obj)
|
||||
{
|
||||
free(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ namespace Models {
|
|||
} Resource;
|
||||
|
||||
inline
|
||||
void freeResource(Resource *obj)
|
||||
void free_Resource(Resource *obj)
|
||||
{
|
||||
if (obj->uri != NULL) {
|
||||
free(obj->uri);
|
||||
|
|
@ -70,18 +70,20 @@ namespace Models {
|
|||
}
|
||||
|
||||
if (obj->info != NULL) {
|
||||
free_ResourceInfo(obj->info);
|
||||
free(obj->info);
|
||||
|
||||
obj->info = NULL;
|
||||
|
||||
}
|
||||
|
||||
if (obj->org != NULL) {
|
||||
freeOrganization(obj->org);
|
||||
free_Organization(obj->org);
|
||||
free(obj->org);
|
||||
|
||||
obj->org = NULL;
|
||||
|
||||
}
|
||||
|
||||
free(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace Models {
|
|||
} ResourceInfo;
|
||||
|
||||
inline
|
||||
void freeResourceInfo(ResourceInfo *obj)
|
||||
void free_ResourceInfo(ResourceInfo *obj)
|
||||
{
|
||||
if (obj->mail != NULL) {
|
||||
free(obj->mail);
|
||||
|
|
@ -36,11 +36,11 @@ namespace Models {
|
|||
}
|
||||
|
||||
if (obj->account != NULL) {
|
||||
freeAccount(obj->account);
|
||||
free_Account(obj->account);
|
||||
free(obj->account);
|
||||
|
||||
obj->account = NULL;
|
||||
}
|
||||
|
||||
free(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ typedef void (*Fptr)(int, char **);
|
|||
|
||||
Stdlib::HashTable::ht *generate_routes()
|
||||
{
|
||||
Stdlib::HashTable::ht *table = Stdlib::HashTable::create_table();
|
||||
Stdlib::HashTable::ht *table = Stdlib::HashTable::create_table(4, true);
|
||||
if (table == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,4 +5,6 @@ sudo apt-get install sqlite3 libsqlite3-dev
|
|||
sudo apt install default-libmysqlclient-dev
|
||||
sudo apt-get install libxml2-dev
|
||||
|
||||
# install maria db https://mariadb.com/docs/connect/programming-languages/cpp/install/
|
||||
# Windows
|
||||
# regex http://gnuwin32.sourceforge.net/packages/pcre.htm
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 641ff4e4e2a7de0db388cf7df73ea3e47e5583dd
|
||||
Subproject commit 7b31df32bccde804f13ed288f4881a27bf6f5ac9
|
||||
|
|
@ -11,6 +11,8 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cOMS/Utils/ApplicationUtils.h"
|
||||
#include "DataStorage/Database/Connection/ConnectionAbstract.h"
|
||||
#include "cOMS/Utils/Parser/Json.h"
|
||||
#include "Stdlib/HashTable.h"
|
||||
|
||||
|
|
@ -20,47 +22,30 @@
|
|||
#define OMS_DEMO false
|
||||
#endif
|
||||
|
||||
void parseConfigFile()
|
||||
{
|
||||
FILE *fp = fopen("config.json", "r");
|
||||
typedef struct {
|
||||
DataStorage::Database::ConnectionAbstract *db;
|
||||
nlohmann::json config;
|
||||
} App;
|
||||
|
||||
nlohmann::json config = nlohmann::json::parse(fp);
|
||||
}
|
||||
|
||||
char *compile_arg_line(int argc, char **argv)
|
||||
{
|
||||
size_t max = 512;
|
||||
size_t length = 0;
|
||||
char *arg = (char *) calloc(max, sizeof(char));
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
size_t argv_length = strlen(argv[i]);
|
||||
if (length + strlen(argv[i]) + 1 > max) {
|
||||
char *tmp = (char *) calloc(max + 128, sizeof(char));
|
||||
memcpy(tmp, arg, (length + 1) * sizeof(char));
|
||||
|
||||
free(arg);
|
||||
arg = tmp;
|
||||
max += 128;
|
||||
}
|
||||
|
||||
strcat(arg, argv[i]);
|
||||
length += argv_length;
|
||||
}
|
||||
|
||||
return arg;
|
||||
}
|
||||
App app;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *arg = compile_arg_line(argc, argv);
|
||||
char *arg = Utils::ApplicationUtils::compile_arg_line(argc, argv);
|
||||
|
||||
// @todo: Check is installed?
|
||||
// no? install
|
||||
// Set program path as cwd
|
||||
char *cwd = Utils::ApplicationUtils::cwd();
|
||||
if (cwd == NULL) {
|
||||
printf("Couldn't get the CWD\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
Utils::ApplicationUtils::chdir_application(cwd, argv[0]);
|
||||
|
||||
// Load config
|
||||
if (!Utils::FileUtils::file_exists("config.json")) {
|
||||
printf("No config file available.");
|
||||
Controller::ApiController::notInstalled(argc, argv);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -77,6 +62,17 @@ int main(int argc, char **argv)
|
|||
(*ptr)(argc, argv);
|
||||
|
||||
Stdlib::HashTable::free_table(routes);
|
||||
free(routes);
|
||||
|
||||
free(arg);
|
||||
arg = NULL;
|
||||
|
||||
// Reset CWD (don't know if this is necessary)
|
||||
#ifdef _WIN32
|
||||
_chdir(cwd);
|
||||
#else
|
||||
chdir(cwd);
|
||||
#endif
|
||||
|
||||
free(cwd);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
class Application
|
||||
{
|
||||
public function run() : string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
280
app/web/Applications/Api/Application.php
Normal file
280
app/web/Applications/Api/Application.php
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Applications\Api;
|
||||
|
||||
use Models\CoreSettings;
|
||||
use Models\SettingsEnum;
|
||||
use Models\AccountMapper;
|
||||
use Models\LocalizationMapper;
|
||||
use Models\NullAccount;
|
||||
use Models\PermissionCategory;
|
||||
use phpOMS\Account\Account;
|
||||
use phpOMS\Account\AccountManager;
|
||||
use phpOMS\Account\PermissionType;
|
||||
use phpOMS\Application\ApplicationAbstract;
|
||||
use phpOMS\Application\ApplicationStatus;
|
||||
use phpOMS\Auth\Auth;
|
||||
use phpOMS\DataStorage\Cache\CachePool;
|
||||
use phpOMS\DataStorage\Cookie\CookieJar;
|
||||
use phpOMS\DataStorage\Database\DatabasePool;
|
||||
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
|
||||
use phpOMS\DataStorage\Session\HttpSession;
|
||||
use phpOMS\Dispatcher\Dispatcher;
|
||||
use phpOMS\Event\EventManager;
|
||||
use phpOMS\Localization\L11nManager;
|
||||
use phpOMS\Message\Http\HttpRequest;
|
||||
use phpOMS\Message\Http\HttpResponse;
|
||||
use phpOMS\Message\Http\RequestStatusCode;
|
||||
use phpOMS\Model\Html\Head;
|
||||
use phpOMS\Module\ModuleManager;
|
||||
use phpOMS\Router\RouteVerb;
|
||||
use phpOMS\Router\WebRouter;
|
||||
use phpOMS\System\File\PathException;
|
||||
use phpOMS\System\MimeType;
|
||||
use phpOMS\Uri\UriFactory;
|
||||
use phpOMS\Views\View;
|
||||
use WebApplication;
|
||||
|
||||
final class Application
|
||||
{
|
||||
|
||||
private WebApplication $app;
|
||||
|
||||
private array $config;
|
||||
|
||||
public function __construct(WebApplication $app, array $config)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->app->appName = 'Api';
|
||||
$this->config = $config;
|
||||
UriFactory::setQuery('/app', \strtolower($this->app->appName));
|
||||
}
|
||||
|
||||
public function run(HttpRequest $request, HttpResponse $response): void
|
||||
{
|
||||
$response->header->set('Content-Type', 'text/plain; charset=utf-8');
|
||||
$pageView = new View($this->app->l11nManager, $request, $response);
|
||||
|
||||
$this->app->l11nManager = new L11nManager($this->app->appName);
|
||||
$this->app->dbPool = new DatabasePool();
|
||||
$this->app->router = new WebRouter();
|
||||
$this->app->router->importFromFile(__DIR__ . '/Routes.php');
|
||||
|
||||
$this->app->sessionManager = new HttpSession(0);
|
||||
$this->app->cookieJar = new CookieJar();
|
||||
$this->app->moduleManager = new ModuleManager($this->app, __DIR__ . '/../../Modules/');
|
||||
$this->app->dispatcher = new Dispatcher($this->app);
|
||||
|
||||
$this->app->dbPool->create('core', $this->config['db']['core']['masters']['admin']);
|
||||
$this->app->dbPool->create('insert', $this->config['db']['core']['masters']['insert']);
|
||||
$this->app->dbPool->create('select', $this->config['db']['core']['masters']['select']);
|
||||
$this->app->dbPool->create('update', $this->config['db']['core']['masters']['update']);
|
||||
$this->app->dbPool->create('delete', $this->config['db']['core']['masters']['delete']);
|
||||
$this->app->dbPool->create('schema', $this->config['db']['core']['masters']['schema']);
|
||||
|
||||
/* Checking csrf token, if a csrf token is required at all has to be decided in the route or controller */
|
||||
if ($request->getData('CSRF') !== null
|
||||
&& !\hash_equals($this->app->sessionManager->get('CSRF'), $request->getData('CSRF'))
|
||||
) {
|
||||
$response->header->status = RequestStatusCode::R_403;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var \phpOMS\DataStorage\Database\Connection\ConnectionAbstract $con */
|
||||
$con = $this->app->dbPool->get();
|
||||
DataMapperFactory::db($con);
|
||||
|
||||
$this->app->cachePool = new CachePool();
|
||||
$this->app->appSettings = new CoreSettings();
|
||||
$this->app->eventManager = new EventManager($this->app->dispatcher);
|
||||
$this->app->eventManager->importFromFile(__DIR__ . '/Hooks.php');
|
||||
|
||||
$this->app->accountManager = new AccountManager($this->app->sessionManager);
|
||||
$this->app->l11nServer = LocalizationMapper::get()->where('id', 1)->execute();
|
||||
|
||||
$this->app->orgId = $this->getApplicationOrganization($request, $this->config['app']);
|
||||
$pageView->setData('orgId', $this->app->orgId);
|
||||
|
||||
$aid = Auth::authenticate($this->app->sessionManager);
|
||||
$request->header->account = $aid;
|
||||
$response->header->account = $aid;
|
||||
|
||||
$account = $this->loadAccount($request);
|
||||
|
||||
if (!($account instanceof NullAccount)) {
|
||||
$response->header->l11n = $account->l11n;
|
||||
} elseif ($this->app->sessionManager->get('language') !== null) {
|
||||
$response->header->l11n
|
||||
->loadFromLanguage(
|
||||
$this->app->sessionManager->get('language'),
|
||||
$this->app->sessionManager->get('country') ?? '*'
|
||||
);
|
||||
} elseif ($this->app->cookieJar->get('language') !== null) {
|
||||
$response->header->l11n
|
||||
->loadFromLanguage(
|
||||
$this->app->cookieJar->get('language'),
|
||||
$this->app->cookieJar->get('country') ?? '*'
|
||||
);
|
||||
}
|
||||
|
||||
UriFactory::setQuery('/lang', $response->getLanguage());
|
||||
$response->header->set('content-language', $response->getLanguage(), true);
|
||||
|
||||
// Cache general settings
|
||||
$this->app->appSettings->get(null, [
|
||||
SettingsEnum::LOGGING_STATUS, SettingsEnum::CLI_ACTIVE,
|
||||
]);
|
||||
|
||||
$appStatus = (int) ($this->app->appSettings->get(null, SettingsEnum::LOGIN_STATUS)->content ?? 0);
|
||||
if ($appStatus === ApplicationStatus::READ_ONLY || $appStatus === ApplicationStatus::DISABLED) {
|
||||
if (!$account->hasPermission(PermissionType::CREATE | PermissionType::MODIFY, module: 'Admin', type: PermissionCategory::APP)) {
|
||||
if ($request->getRouteVerb() !== RouteVerb::GET) {
|
||||
// Application is in read only mode or completely disabled
|
||||
// If read only mode is active only GET requests are allowed
|
||||
// A user who is part of the admin group is excluded from this rule
|
||||
$response->header->status = RequestStatusCode::R_405;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->app->dbPool->remove('admin');
|
||||
$this->app->dbPool->remove('insert');
|
||||
$this->app->dbPool->remove('update');
|
||||
$this->app->dbPool->remove('delete');
|
||||
$this->app->dbPool->remove('schema');
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($uris = $request->uri->getQuery('r'))) {
|
||||
$this->handleBatchRequest($uris, $request, $response);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->app->moduleManager->initRequestModules($request);
|
||||
|
||||
// add tpl loading
|
||||
$this->app->router->add(
|
||||
'/api/tpl/.*',
|
||||
function () use ($account, $request, $response): void {
|
||||
$appName = \ucfirst($request->getData('app') ?? 'Backend');
|
||||
$app = new class() extends ApplicationAbstract
|
||||
{
|
||||
};
|
||||
|
||||
$app->appName = $appName;
|
||||
$app->dbPool = $this->app->dbPool;
|
||||
$app->orgId = $this->app->orgId;
|
||||
$app->accountManager = $this->app->accountManager;
|
||||
$app->appSettings = $this->app->appSettings;
|
||||
$app->l11nManager = new L11nManager($app->appName);
|
||||
$app->moduleManager = new ModuleManager($app, __DIR__ . '/../../Modules/');
|
||||
$app->dispatcher = new Dispatcher($app);
|
||||
$app->eventManager = new EventManager($app->dispatcher);
|
||||
$app->router = new WebRouter();
|
||||
|
||||
$app->eventManager->importFromFile(__DIR__ . '/../' . $appName . '/Hooks.php');
|
||||
$app->router->importFromFile(__DIR__ . '/../' . $appName . '/Routes.php');
|
||||
|
||||
$route = \str_replace('/api/tpl', '/' . $appName, $request->uri->getRoute());
|
||||
|
||||
$view = new View();
|
||||
$view->setTemplate('/Web/Api/index');
|
||||
|
||||
$response->set('Content', $view);
|
||||
$response->get('Content')->setData('head', new Head());
|
||||
|
||||
$app->l11nManager->loadLanguage(
|
||||
$response->getLanguage(),
|
||||
'0',
|
||||
include __DIR__ . '/../' . $appName . '/lang/' . $response->getLanguage() . '.lang.php'
|
||||
);
|
||||
|
||||
$routed = $app->router->route(
|
||||
$route,
|
||||
$request->getData('CSRF'),
|
||||
$request->getRouteVerb(),
|
||||
$appName,
|
||||
$this->app->orgId,
|
||||
$account,
|
||||
$request->getData()
|
||||
);
|
||||
|
||||
$response->get('Content')->setData('dispatch', $app->dispatcher->dispatch($routed, $request, $response));
|
||||
},
|
||||
RouteVerb::GET
|
||||
);
|
||||
|
||||
$routed = $this->app->router->route(
|
||||
$request->uri->getRoute(),
|
||||
$request->getData('CSRF'),
|
||||
$request->getRouteVerb(),
|
||||
$this->app->appName,
|
||||
$this->app->orgId,
|
||||
$account,
|
||||
$request->getData()
|
||||
);
|
||||
|
||||
$dispatched = $this->app->dispatcher->dispatch($routed, $request, $response);
|
||||
|
||||
if (empty($dispatched)) {
|
||||
$response->header->set('Content-Type', MimeType::M_JSON . '; charset=utf-8', true);
|
||||
$response->header->status = RequestStatusCode::R_404;
|
||||
$response->set($request->uri->__toString(), [
|
||||
'status' => \phpOMS\Message\NotificationLevel::ERROR,
|
||||
'title' => '',
|
||||
'message' => '',
|
||||
'response' => [],
|
||||
]);
|
||||
}
|
||||
|
||||
$pageView->addData('dispatch', $dispatched);
|
||||
}
|
||||
|
||||
private function loadAccount(HttpRequest $request): Account
|
||||
{
|
||||
$account = AccountMapper::getWithPermissions($request->header->account);
|
||||
$this->app->accountManager->add($account);
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
private function handleBatchRequest(string $uris, HttpRequest $request, HttpResponse $response): void
|
||||
{
|
||||
$request_r = clone $request;
|
||||
$uris = \json_decode($uris, true);
|
||||
|
||||
foreach ($uris as $uri) {
|
||||
$modules = $this->app->moduleManager->getRoutedModules($request_r);
|
||||
$this->app->moduleManager->initModule($modules);
|
||||
|
||||
$this->app->dispatcher->dispatch(
|
||||
$this->app->router->route(
|
||||
$request->uri->getRoute(),
|
||||
$request->getData('CSRF') ?? null
|
||||
),
|
||||
$request,
|
||||
$response
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function getApplicationOrganization(HttpRequest $request, array $config): int
|
||||
{
|
||||
return (int) ($request->getData('u') ?? ($config['domains'][$request->uri->host]['org'] ?? $config['default']['org']));
|
||||
}
|
||||
|
||||
private function loadLanguageFromPath(string $language, string $path): void
|
||||
{
|
||||
/* Load theme language */
|
||||
if (($absPath = \realpath($path)) === false) {
|
||||
throw new PathException($path);
|
||||
}
|
||||
|
||||
/** @noinspection PhpIncludeInspection */
|
||||
$themeLanguage = include $absPath;
|
||||
$this->app->l11nManager->loadLanguage($language, '0', $themeLanguage);
|
||||
}
|
||||
}
|
||||
53
app/web/Applications/E500/Application.php
Normal file
53
app/web/Applications/E500/Application.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Applications\E500;
|
||||
|
||||
use phpOMS\Asset\AssetType;
|
||||
use phpOMS\Localization\L11nManager;
|
||||
use phpOMS\Message\Http\HttpRequest;
|
||||
use phpOMS\Message\Http\HttpResponse;
|
||||
use phpOMS\Message\Http\RequestStatusCode;
|
||||
use phpOMS\Model\Html\Head;
|
||||
use phpOMS\System\File\PathException;
|
||||
use phpOMS\Views\View;
|
||||
use WebApplication;
|
||||
|
||||
final class Application
|
||||
{
|
||||
private WebApplication $app;
|
||||
|
||||
private array $config = [];
|
||||
|
||||
public function __construct(WebApplication $app, array $config)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->config = $config;
|
||||
$this->app->appName = 'E500';
|
||||
}
|
||||
|
||||
public function run(HttpRequest $request, HttpResponse $response) : void
|
||||
{
|
||||
$pageView = new View($this->app->l11nManager, $request, $response);
|
||||
$pageView->setTemplate('/Applications/E500/index');
|
||||
$response->set('Content', $pageView);
|
||||
$response->header->status = RequestStatusCode::R_500;
|
||||
|
||||
/* Load theme language */
|
||||
if (($path = \realpath($oldPath = __DIR__ . '/lang/' . $response->getLanguage() . '.lang.php')) === false) {
|
||||
throw new PathException($oldPath);
|
||||
}
|
||||
|
||||
$this->app->l11nManager = new L11nManager($this->app->appName);
|
||||
|
||||
/** @noinspection PhpIncludeInspection */
|
||||
$themeLanguage = include $path;
|
||||
$this->app->l11nManager->loadLanguage($response->getLanguage(), '0', $themeLanguage);
|
||||
|
||||
$head = new Head();
|
||||
$baseUri = $request->uri->getBase();
|
||||
$head->addAsset(AssetType::CSS, $baseUri . 'cssOMS/styles.css?v=1.0.0');
|
||||
|
||||
$pageView->setData('head', $head);
|
||||
}
|
||||
}
|
||||
275
app/web/Install/Application.php
Normal file
275
app/web/Install/Application.php
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package Install
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://karaka.app
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Install;
|
||||
|
||||
use phpOMS\DataStorage\Database\DatabaseStatus;
|
||||
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
|
||||
use phpOMS\Dispatcher\Dispatcher;
|
||||
use phpOMS\Localization\ISO639x1Enum;
|
||||
use phpOMS\Localization\Localization;
|
||||
use phpOMS\Log\FileLogger;
|
||||
use phpOMS\Message\Http\HttpRequest;
|
||||
use phpOMS\Message\Http\HttpResponse;
|
||||
use phpOMS\Message\Http\RequestStatusCode;
|
||||
use phpOMS\Router\RouteVerb;
|
||||
use phpOMS\Router\WebRouter;
|
||||
use phpOMS\System\MimeType;
|
||||
use phpOMS\Uri\UriFactory;
|
||||
use phpOMS\Views\View;
|
||||
|
||||
/**
|
||||
* Application class.
|
||||
*
|
||||
* @package Install
|
||||
* @license OMS License 1.0
|
||||
* @link https://karaka.app
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @property \phpOMS\Router\WebRouter $router
|
||||
*/
|
||||
final class WebApplication extends InstallAbstract
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $config Core config
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct(array $config)
|
||||
{
|
||||
$this->setupHandlers();
|
||||
|
||||
$this->logger = FileLogger::getInstance($config['log']['file']['path'], false);
|
||||
$request = $this->initRequest($config['page']['root'], $config['language'][0]);
|
||||
$response = $this->initResponse($request, $config['language']);
|
||||
|
||||
UriFactory::setupUriBuilder($request->uri);
|
||||
|
||||
$this->run($request, $response);
|
||||
|
||||
$response->header->push();
|
||||
echo $response->getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize current application request
|
||||
*
|
||||
* @param string $rootPath Web root path
|
||||
* @param string $language Fallback language
|
||||
*
|
||||
* @return HttpRequest Initial client request
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function initRequest(string $rootPath, string $language) : HttpRequest
|
||||
{
|
||||
$request = HttpRequest::createFromSuperglobals();
|
||||
$subDirDepth = \substr_count($rootPath, '/');
|
||||
|
||||
$request->createRequestHashs($subDirDepth);
|
||||
$request->uri->setRootPath($rootPath);
|
||||
UriFactory::setupUriBuilder($request->uri);
|
||||
|
||||
$langCode = \strtolower($request->uri->getPathElement(0));
|
||||
$request->header->l11n->setLanguage(
|
||||
empty($langCode) || !ISO639x1Enum::isValidValue($langCode) ? $language : $langCode
|
||||
);
|
||||
UriFactory::setQuery('/lang', $request->getLanguage());
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize basic response
|
||||
*
|
||||
* @param HttpRequest $request Client request
|
||||
* @param array $languages Supported languages
|
||||
*
|
||||
* @return HttpResponse Initial client request
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function initResponse(HttpRequest $request, array $languages) : HttpResponse
|
||||
{
|
||||
$response = new HttpResponse(new Localization());
|
||||
$response->header->set('content-type', 'text/html; charset=utf-8');
|
||||
$response->header->set('x-xss-protection', '1; mode=block');
|
||||
$response->header->set('x-content-type-options', 'nosniff');
|
||||
$response->header->set('x-frame-options', 'SAMEORIGIN');
|
||||
$response->header->set('referrer-policy', 'same-origin');
|
||||
|
||||
if ($request->isHttps()) {
|
||||
$response->header->set('strict-transport-security', 'max-age=31536000');
|
||||
}
|
||||
|
||||
$response->header->l11n->setLanguage(
|
||||
!\in_array($request->getLanguage(), $languages) ? 'en' : $request->getLanguage()
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendering backend.
|
||||
*
|
||||
* @param HttpRequest $request Request
|
||||
* @param HttpResponse $response Response
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function run(HttpRequest $request, HttpResponse $response) : void
|
||||
{
|
||||
$this->dispatcher = new Dispatcher($this);
|
||||
$this->router = new WebRouter();
|
||||
|
||||
$this->setupRoutes();
|
||||
$response->header->set('content-language', $response->getLanguage(), true);
|
||||
UriFactory::setQuery('/lang', $response->getLanguage());
|
||||
|
||||
$this->dispatcher->dispatch(
|
||||
$this->router->route(
|
||||
$request->uri->getRoute(),
|
||||
$request->getData('CSRF'),
|
||||
$request->getRouteVerb()
|
||||
),
|
||||
$request,
|
||||
$response
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup routes for installer
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function setupRoutes() : void
|
||||
{
|
||||
$this->router->add('^.*', '\Install\WebApplication::installView', RouteVerb::GET);
|
||||
$this->router->add('^.*', '\Install\WebApplication::installRequest', RouteVerb::PUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create install view
|
||||
*
|
||||
* @param HttpRequest $request Request
|
||||
* @param HttpResponse $response Response
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public static function installView(HttpRequest $request, HttpResponse $response) : void
|
||||
{
|
||||
$view = new View(null, $request, $response);
|
||||
$view->setTemplate('/Install/index');
|
||||
$response->set('Content', $view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle install request.
|
||||
*
|
||||
* @param HttpRequest $request Request
|
||||
* @param HttpResponse $response Response
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function installRequest(HttpRequest $request, HttpResponse $response) : void
|
||||
{
|
||||
$response->header->set('Content-Type', MimeType::M_JSON . '; charset=utf-8', true);
|
||||
|
||||
if (!empty(self::validateRequest($request))) {
|
||||
$response->header->status = RequestStatusCode::R_400;
|
||||
return;
|
||||
}
|
||||
|
||||
$db = self::setupDatabaseConnection($request);
|
||||
$db->connect();
|
||||
|
||||
if ($db->getStatus() !== DatabaseStatus::OK) {
|
||||
$response->header->status = RequestStatusCode::R_400;
|
||||
return;
|
||||
}
|
||||
|
||||
DataMapperFactory::db($db);
|
||||
|
||||
self::clearOld();
|
||||
self::installConfigFile($request);
|
||||
self::installCore($db);
|
||||
self::installGroups($db);
|
||||
self::installUsers($request, $db);
|
||||
self::installApplications($request, $db);
|
||||
self::configureCoreModules($request, $db);
|
||||
|
||||
$response->header->status = RequestStatusCode::R_200;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate install request.
|
||||
*
|
||||
* @param HttpRequest $request Request
|
||||
*
|
||||
* @return array<string, bool>
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private static function validateRequest(HttpRequest $request) : array
|
||||
{
|
||||
$valid = [];
|
||||
|
||||
if (($valid['php_extensions'] = !self::hasPhpExtensions())
|
||||
|| ($valid['iDbHost'] = empty($request->getData('dbhost')))
|
||||
|| ($valid['iDbType'] = empty($request->getData('dbtype')))
|
||||
|| ($valid['iDbPort'] = empty($request->getData('dbport')))
|
||||
|| ($valid['iDbName'] = empty($request->getData('dbname')))
|
||||
|| ($valid['iSchemaUser'] = empty($request->getData('schemauser')))
|
||||
//|| ($valid['iSchemaPassword'] = empty($request->getData('schemapassword')))
|
||||
|| ($valid['iCreateUser'] = empty($request->getData('createuser')))
|
||||
//|| ($valid['iCreatePassword'] = empty($request->getData('createpassword')))
|
||||
|| ($valid['iSelectUser'] = empty($request->getData('selectuser')))
|
||||
//|| ($valid['iSelectPassword'] = empty($request->getData('selectpassword')))
|
||||
|| ($valid['iDeleteUser'] = empty($request->getData('deleteuser')))
|
||||
//|| ($valid['iDeletePassword'] = empty($request->getData('deletepassword')))
|
||||
|| ($valid['iDbName'] = !self::testDbConnection($request))
|
||||
|| ($valid['iOrgName'] = empty($request->getData('orgname')))
|
||||
|| ($valid['iAdminName'] = empty($request->getData('adminname')))
|
||||
//|| ($valid['iAdminPassword'] = empty($request->getData('adminpassword')))
|
||||
|| ($valid['iAdminEmail'] = empty($request->getData('adminemail')))
|
||||
|| ($valid['iDomain'] = empty($request->getData('domain')))
|
||||
|| ($valid['iWebSubdir'] = empty($request->getData('websubdir')))
|
||||
|| ($valid['iDefaultLang'] = empty($request->getData('defaultlang')))
|
||||
) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
433
app/web/Install/InstallAbstract.php
Normal file
433
app/web/Install/InstallAbstract.php
Normal file
|
|
@ -0,0 +1,433 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package Install
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://karaka.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Install;
|
||||
|
||||
use Models\CoreSettings;
|
||||
use Models\Account;
|
||||
use Models\AccountCredentialMapper;
|
||||
use Models\Group;
|
||||
use Models\GroupMapper;
|
||||
use Models\GroupPermission;
|
||||
use Models\GroupPermissionMapper;
|
||||
use Models\PermissionCategory;
|
||||
use Models\ModuleStatusUpdateType;
|
||||
use Models\NullAccount;
|
||||
use phpOMS\Account\AccountManager;
|
||||
use phpOMS\Account\AccountStatus;
|
||||
use phpOMS\Account\AccountType;
|
||||
use phpOMS\Account\GroupStatus;
|
||||
use phpOMS\Account\PermissionType;
|
||||
use phpOMS\Application\ApplicationAbstract;
|
||||
use phpOMS\DataStorage\Database\Connection\ConnectionAbstract;
|
||||
use phpOMS\DataStorage\Database\Connection\ConnectionFactory;
|
||||
use phpOMS\DataStorage\Database\DatabasePool;
|
||||
use phpOMS\DataStorage\Database\Schema\Builder as SchemaBuilder;
|
||||
use phpOMS\DataStorage\Session\HttpSession;
|
||||
use phpOMS\Dispatcher\Dispatcher;
|
||||
use phpOMS\Event\EventManager;
|
||||
use phpOMS\Localization\Localization;
|
||||
use phpOMS\Message\Http\HttpRequest;
|
||||
use phpOMS\Message\Http\HttpResponse;
|
||||
use phpOMS\Message\RequestAbstract;
|
||||
use phpOMS\Module\ModuleManager;
|
||||
use phpOMS\System\File\Local\Directory;
|
||||
use phpOMS\System\MimeType;
|
||||
use phpOMS\Uri\HttpUri;
|
||||
use phpOMS\Utils\IO\Zip\Zip;
|
||||
use phpOMS\Utils\TestUtils;
|
||||
|
||||
/**
|
||||
* Application class.
|
||||
*
|
||||
* @package Install
|
||||
* @license OMS License 1.0
|
||||
* @link https://karaka.app
|
||||
* @since 1.0.0
|
||||
*/
|
||||
abstract class InstallAbstract extends ApplicationAbstract
|
||||
{
|
||||
/**
|
||||
* Module manager
|
||||
*
|
||||
* @var null|ModuleManager
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static ?ModuleManager $mManager = null;
|
||||
|
||||
/**
|
||||
* Setup general handlers for the application.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function setupHandlers() : void
|
||||
{
|
||||
\set_exception_handler(['\phpOMS\UnhandledHandler', 'exceptionHandler']);
|
||||
\set_error_handler(['\phpOMS\UnhandledHandler', 'errorHandler']);
|
||||
\register_shutdown_function(['\phpOMS\UnhandledHandler', 'shutdownHandler']);
|
||||
\mb_internal_encoding('UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear old install
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static function clearOld() : void
|
||||
{
|
||||
\file_put_contents(__DIR__ . '/../Cli/Routes.php', '<?php return [];');
|
||||
\file_put_contents(__DIR__ . '/../Cli/Hooks.php', '<?php return [];');
|
||||
|
||||
$dirs = \scandir(__DIR__ . '/../Web');
|
||||
if ($dirs === false) {
|
||||
return; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
foreach ($dirs as $dir) {
|
||||
if ($dir === '.' || $dir === '..'
|
||||
|| $dir === 'Exception'
|
||||
|| $dir === 'WebApplication.php'
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Directory::delete(__DIR__ . '/../Web/' . $dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if has certain php extensions enabled
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static function hasPhpExtensions() : bool
|
||||
{
|
||||
return \extension_loaded('pdo')
|
||||
&& \extension_loaded('mbstring');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if database connection is correct and working
|
||||
*
|
||||
* @param RequestAbstract $request Request
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static function testDbConnection(RequestAbstract $request) : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create database connection
|
||||
*
|
||||
* @param RequestAbstract $request Request
|
||||
*
|
||||
* @return ConnectionAbstract
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static function setupDatabaseConnection(RequestAbstract $request) : ConnectionAbstract
|
||||
{
|
||||
return ConnectionFactory::create([
|
||||
'db' => (string) $request->getData('dbtype'),
|
||||
'host' => (string) $request->getData('dbhost'),
|
||||
'port' => (int) $request->getData('dbport'),
|
||||
'database' => (string) $request->getData('dbname'),
|
||||
'login' => (string) $request->getData('schemauser'),
|
||||
'password' => (string) $request->getData('schemapassword'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Install/setup configuration
|
||||
*
|
||||
* @param RequestAbstract $request Request
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static function installConfigFile(RequestAbstract $request) : void
|
||||
{
|
||||
self::editConfigFile($request);
|
||||
self::editHtaccessFile($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify config file
|
||||
*
|
||||
* @param RequestAbstract $request Request
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static function editConfigFile(RequestAbstract $request) : void
|
||||
{
|
||||
$db = $request->getData('dbtype');
|
||||
$host = $request->getData('dbhost');
|
||||
$port = (int) $request->getData('dbport');
|
||||
$dbname = $request->getData('dbname');
|
||||
|
||||
$admin = ['login' => $request->getData('schemauser'), 'password' => $request->getData('schemapassword')];
|
||||
$insert = ['login' => $request->getData('createuser'), 'password' => $request->getData('createpassword')];
|
||||
$select = ['login' => $request->getData('selectuser'), 'password' => $request->getData('selectpassword')];
|
||||
$update = ['login' => $request->getData('updateuser'), 'password' => $request->getData('updatepassword')];
|
||||
$delete = ['login' => $request->getData('deleteuser'), 'password' => $request->getData('deletepassword')];
|
||||
$schema = ['login' => $request->getData('schemauser'), 'password' => $request->getData('schemapassword')];
|
||||
|
||||
$subdir = $request->getData('websubdir');
|
||||
$tld = $request->getData('domain');
|
||||
|
||||
$tldOrg = 1;
|
||||
$defaultOrg = 1;
|
||||
|
||||
$config = include __DIR__ . '/Templates/config.tpl.php';
|
||||
|
||||
\file_put_contents(__DIR__ . '/../config.php', $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify htaccess file
|
||||
*
|
||||
* @param RequestAbstract $request Request
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static function editHtaccessFile(RequestAbstract $request) : void
|
||||
{
|
||||
$fullTLD = $request->getData('domain');
|
||||
$tld = \str_replace(['.', 'http://', 'https://'], ['\.', '', ''], $request->getData('domain') ?? '');
|
||||
$subPath = $request->getData('websubdir') ?? '/';
|
||||
|
||||
$config = include __DIR__ . '/Templates/htaccess.tpl.php';
|
||||
|
||||
\file_put_contents(__DIR__ . '/../.htaccess', $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Install core functionality
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static function installCore(ConnectionAbstract $db) : void
|
||||
{
|
||||
self::createBaseTables($db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create module table
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static function createBaseTables(ConnectionAbstract $db) : void
|
||||
{
|
||||
$path = __DIR__ . '/db.json';
|
||||
if (!\is_file($path)) {
|
||||
return; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$content = \file_get_contents($path);
|
||||
if ($content === false) {
|
||||
return; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$definitions = \json_decode($content, true);
|
||||
foreach ($definitions as $definition) {
|
||||
SchemaBuilder::createFromSchema($definition, $db)->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Install basic groups
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static function installGroups(ConnectionAbstract $db) : void
|
||||
{
|
||||
self::installMainGroups($db);
|
||||
self::installGroupPermissions($db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create basic groups in db
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static function installMainGroups(ConnectionAbstract $db) : void
|
||||
{
|
||||
$guest = new Group('guest');
|
||||
$guest->setStatus(GroupStatus::ACTIVE);
|
||||
GroupMapper::create()->execute($guest);
|
||||
|
||||
$user = new Group('user');
|
||||
$user->setStatus(GroupStatus::ACTIVE);
|
||||
GroupMapper::create()->execute($user);
|
||||
|
||||
$admin = new Group('admin');
|
||||
$admin->setStatus(GroupStatus::ACTIVE);
|
||||
GroupMapper::create()->execute($admin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set permissions of basic groups
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static function installGroupPermissions(ConnectionAbstract $db) : void
|
||||
{
|
||||
$searchPermission = new GroupPermission(
|
||||
group: 2,
|
||||
category: PermissionCategory::SEARCH,
|
||||
permission: PermissionType::READ
|
||||
);
|
||||
|
||||
$adminPermission = new GroupPermission(
|
||||
group: 3,
|
||||
permission: PermissionType::READ | PermissionType::CREATE | PermissionType::MODIFY | PermissionType::DELETE | PermissionType::PERMISSION
|
||||
);
|
||||
|
||||
GroupPermissionMapper::create()->execute($searchPermission);
|
||||
GroupPermissionMapper::create()->execute($adminPermission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Install users
|
||||
*
|
||||
* @param RequestAbstract $request Request
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static function installUsers(RequestAbstract $request, ConnectionAbstract $db) : void
|
||||
{
|
||||
self::installMainUser($request, $db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Install applications
|
||||
*
|
||||
* @param RequestAbstract $request Request
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static function installApplications(RequestAbstract $request, ConnectionAbstract $db) : void
|
||||
{
|
||||
if (self::$mManager === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$apps = $request->getDataList('apps');
|
||||
$theme = 'Default';
|
||||
|
||||
/** @var \Modules\CMS\Controller\ApiController $module */
|
||||
$module = self::$mManager->get('CMS');
|
||||
|
||||
foreach ($apps as $app) {
|
||||
$temp = new HttpRequest(new HttpUri(''));
|
||||
$temp->header->account = 1;
|
||||
$temp->setData('name', \basename($app));
|
||||
$temp->setData('theme', $theme);
|
||||
|
||||
Zip::pack(__DIR__ . '/../' . $app, __DIR__ . '/' . \basename($app) . '.zip');
|
||||
|
||||
TestUtils::setMember($temp, 'files', [
|
||||
[
|
||||
'name' => \basename($app) . '.zip',
|
||||
'type' => MimeType::M_ZIP,
|
||||
'tmp_name' => __DIR__ . '/' . \basename($app) . '.zip',
|
||||
'error' => \UPLOAD_ERR_OK,
|
||||
'size' => \filesize(__DIR__ . '/' . \basename($app) . '.zip'),
|
||||
],
|
||||
]);
|
||||
|
||||
$module->apiApplicationInstall($temp, new HttpResponse());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup root user in database
|
||||
*
|
||||
* @param RequestAbstract $request Request
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected static function installMainUser(RequestAbstract $request, ConnectionAbstract $db) : void
|
||||
{
|
||||
$account = new Account();
|
||||
$account->setStatus(AccountStatus::ACTIVE);
|
||||
$account->tries = 0;
|
||||
$account->setType(AccountType::USER);
|
||||
$account->login = (string) $request->getData('adminname');
|
||||
$account->name1 = (string) $request->getData('adminname');
|
||||
$account->generatePassword((string) $request->getData('adminpassword'));
|
||||
$account->setEmail((string) $request->getData('adminemail'));
|
||||
|
||||
$l11n = $account->l11n;
|
||||
$l11n->loadFromLanguage($request->getData('defaultlang') ?? 'en', $request->getData('defaultcountry') ?? 'us');
|
||||
|
||||
AccountCredentialMapper::create()->execute($account);
|
||||
|
||||
$sth = $db->con->prepare(
|
||||
'INSERT INTO `account_group` (`account_group_group`, `account_group_account`) VALUES
|
||||
(3, ' . $account->getId() . ');'
|
||||
);
|
||||
|
||||
if ($sth === false) {
|
||||
return; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$sth->execute();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Install;
|
||||
|
||||
class Install
|
||||
{
|
||||
private function installDB()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
172
app/web/Install/Templates/config.tpl.php
Executable file
172
app/web/Install/Templates/config.tpl.php
Executable file
|
|
@ -0,0 +1,172 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package Template
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://karaka.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @var string $db Database
|
||||
* @var string $host Host
|
||||
* @var int $port Port
|
||||
* @var array{login:string, password:string} $admin Admin login data
|
||||
* @var array{login:string, password:string} $insert Insert login data
|
||||
* @var array{login:string, password:string} $select Select login data
|
||||
* @var array{login:string, password:string} $update Update login data
|
||||
* @var array{login:string, password:string} $delete Delete login data
|
||||
* @var array{login:string, password:string} $schema Schema login data
|
||||
* @var string $dbname Database name
|
||||
* @var string $subdir Subdirectory path
|
||||
* @var string $tld Top level domain
|
||||
*/
|
||||
return <<<EOT
|
||||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package Install
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://karaka.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'db' => [
|
||||
'core' => [
|
||||
'masters' => [
|
||||
'admin' => [
|
||||
'db' => '${db}', /* db type */
|
||||
'host' => '${host}', /* db host address */
|
||||
'port' => '${port}', /* db host port */
|
||||
'login' => '{$admin['login']}', /* db login name */
|
||||
'password' => '{$admin['password']}', /* db login password */
|
||||
'database' => '${dbname}', /* db name */
|
||||
'weight' => 1000, /* db table weight */
|
||||
],
|
||||
'insert' => [
|
||||
'db' => '${db}', /* db type */
|
||||
'host' => '${host}', /* db host address */
|
||||
'port' => '${port}', /* db host port */
|
||||
'login' => '{$insert['login']}', /* db login name */
|
||||
'password' => '{$insert['password']}', /* db login password */
|
||||
'database' => '${dbname}', /* db name */
|
||||
'weight' => 1000, /* db table weight */
|
||||
],
|
||||
'select' => [
|
||||
'db' => '${db}', /* db type */
|
||||
'host' => '${host}', /* db host address */
|
||||
'port' => '${port}', /* db host port */
|
||||
'login' => '{$select['login']}', /* db login name */
|
||||
'password' => '{$select['password']}', /* db login password */
|
||||
'database' => '${dbname}', /* db name */
|
||||
'weight' => 1000, /* db table weight */
|
||||
],
|
||||
'update' => [
|
||||
'db' => '${db}', /* db type */
|
||||
'host' => '${host}', /* db host address */
|
||||
'port' => '${port}', /* db host port */
|
||||
'login' => '{$update['login']}', /* db login name */
|
||||
'password' => '{$update['password']}', /* db login password */
|
||||
'database' => '${dbname}', /* db name */
|
||||
'weight' => 1000, /* db table weight */
|
||||
],
|
||||
'delete' => [
|
||||
'db' => '${db}', /* db type */
|
||||
'host' => '${host}', /* db host address */
|
||||
'port' => '${port}', /* db host port */
|
||||
'login' => '{$delete['login']}', /* db login name */
|
||||
'password' => '{$delete['password']}', /* db login password */
|
||||
'database' => '${dbname}', /* db name */
|
||||
'weight' => 1000, /* db table weight */
|
||||
],
|
||||
'schema' => [
|
||||
'db' => '${db}', /* db type */
|
||||
'host' => '${host}', /* db host address */
|
||||
'port' => '${port}', /* db host port */
|
||||
'login' => '{$schema['login']}', /* db login name */
|
||||
'password' => '{$schema['password']}', /* db login password */
|
||||
'database' => '${dbname}', /* db name */
|
||||
'weight' => 1000, /* db table weight */
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'mail' => [
|
||||
'imap' => [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 143,
|
||||
'ssl' => false,
|
||||
'user' => 'test',
|
||||
'password' => '123456',
|
||||
],
|
||||
'pop3' => [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 25,
|
||||
'ssl' => false,
|
||||
'user' => 'test',
|
||||
'password' => '123456',
|
||||
],
|
||||
],
|
||||
'cache' => [
|
||||
'redis' => [
|
||||
'db' => 1,
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379,
|
||||
],
|
||||
'memcached' => [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 11211,
|
||||
],
|
||||
],
|
||||
'log' => [
|
||||
'file' => [
|
||||
'path' => __DIR__ . '/Logs',
|
||||
],
|
||||
],
|
||||
'page' => [
|
||||
'root' => '${subdir}',
|
||||
'https' => false,
|
||||
],
|
||||
'app' => [
|
||||
'path' => __DIR__,
|
||||
'default' => [
|
||||
'app' => 'Backend',
|
||||
'id' => 'backend',
|
||||
'lang' => 'en',
|
||||
'theme' => 'Backend',
|
||||
'org' => ${defaultOrg},
|
||||
],
|
||||
'domains' => [
|
||||
'${tld}' => [
|
||||
'app' => 'Backend',
|
||||
'id' => 'backend',
|
||||
'lang' => 'en',
|
||||
'theme' => 'Backend',
|
||||
'org' => ${tldOrg},
|
||||
],
|
||||
],
|
||||
],
|
||||
'socket' => [
|
||||
'master' => [
|
||||
'host' => '${tld}',
|
||||
'limit' => 300,
|
||||
'port' => 4310,
|
||||
],
|
||||
],
|
||||
'language' => [
|
||||
'en', 'de', 'it',
|
||||
],
|
||||
];
|
||||
|
||||
EOT;
|
||||
153
app/web/Install/Templates/htaccess.tpl.php
Executable file
153
app/web/Install/Templates/htaccess.tpl.php
Executable file
|
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package Template
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://karaka.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
$htaccess = <<<EOT
|
||||
# BEGIN Gzip Compression
|
||||
<ifmodule mod_rewrite.c>
|
||||
AddEncoding gzip .gz
|
||||
<filesmatch "\.js\.gz$">
|
||||
AddType "text/javascript" .gz
|
||||
</filesmatch>
|
||||
<filesmatch "\.css\.gz$">
|
||||
AddType "text/css" .gz
|
||||
</filesmatch>
|
||||
</ifmodule>
|
||||
|
||||
AddType font/ttf .ttf
|
||||
AddType font/otf .otf
|
||||
AddType application/font-woff .woff
|
||||
AddType application/vnd.ms-fontobject .eot
|
||||
|
||||
<ifmodule mod_deflate.c>
|
||||
AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css application/x-javascript application/javascript text/javascript
|
||||
</ifmodule>
|
||||
# END Gzip Compression
|
||||
|
||||
# Force mime for javascript files
|
||||
<Files "*.js">
|
||||
ForceType text/javascript
|
||||
</Files>
|
||||
|
||||
# BEGIN Caching
|
||||
<ifModule mod_expires.c>
|
||||
ExpiresActive On
|
||||
ExpiresDefault A300
|
||||
|
||||
ExpiresByType image/x-icon A2592000
|
||||
|
||||
<FilesMatch ".(php)$">
|
||||
ExpiresDefault A0
|
||||
Header set Cache-Control "no-store, no-cache, must-revalidate, max-age=0"
|
||||
Header set Pragma "no-cache"
|
||||
</FilesMatch>
|
||||
</ifModule>
|
||||
# END Caching
|
||||
|
||||
# BEGIN Spelling
|
||||
<IfModule mod_speling.c>
|
||||
CheckSpelling On
|
||||
CheckCaseOnly On
|
||||
</IfModule>
|
||||
# END Spelling
|
||||
|
||||
# BEGIN URL rewrite
|
||||
<ifmodule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteBase /
|
||||
RewriteCond %{HTTP:Accept-encoding} gzip
|
||||
RewriteCond %{REQUEST_FILENAME} \.(js|css)$
|
||||
RewriteCond %{REQUEST_FILENAME}.gz -f
|
||||
RewriteRule ^(.*)$ $1.gz [QSA,L]
|
||||
|
||||
EOT;
|
||||
|
||||
if (\stripos($fullTLD, '127.0.0.1') === false) {
|
||||
if (\filter_var($fullTLD, \FILTER_VALIDATE_IP) === false) {
|
||||
$htaccess .= <<<EOT
|
||||
RewriteCond %{HTTP_HOST} !^www.*$ [L]
|
||||
|
||||
EOT;
|
||||
}
|
||||
|
||||
$htaccess .= <<<EOT
|
||||
RewriteCond %{HTTP_HOST} ^(.*)\.${tld}
|
||||
RewriteRule ^([a-zA-Z]{2})\/(.*)$ ${fullTLD}/$1/%1/$2 [QSA]
|
||||
|
||||
EOT;
|
||||
}
|
||||
|
||||
$htaccess .= <<<EOT
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^(.*)$
|
||||
EOT;
|
||||
|
||||
$htaccess .= ' ' . $subPath;
|
||||
|
||||
$htaccess .= <<<EOT
|
||||
?{QUERY_STRING} [QSA]
|
||||
|
||||
EOT;
|
||||
|
||||
$htaccess .= <<< EOT
|
||||
RewriteCond %{HTTPS} !on
|
||||
RewriteCond %{HTTP_HOST} !^(127\.0\.0)|(192\.)|(172\.)
|
||||
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
|
||||
</ifmodule>
|
||||
# END URL rewrite
|
||||
|
||||
# BEGIN Access control
|
||||
<Files *.php>
|
||||
Order Deny,Allow
|
||||
Deny from all
|
||||
Allow from 127.0.0.1
|
||||
</Files>
|
||||
<Files index.php>
|
||||
Allow from all
|
||||
</Files>
|
||||
# END Access control
|
||||
|
||||
# Disable directory view
|
||||
Options All -Indexes
|
||||
|
||||
# Disable unsupported scripts
|
||||
Options -ExecCGI
|
||||
AddHandler cgi-script .pl .py .jsp .asp .shtml .sh .cgi
|
||||
|
||||
#<ifmodule mod_headers.c>
|
||||
# # XSS protection
|
||||
# header always set x-xss-protection "1; mode=block"
|
||||
#
|
||||
# # Nosnif
|
||||
# header always set x-content-type-options "nosniff"
|
||||
#
|
||||
# # Iframes only from self
|
||||
# header always set x-frame-options "SAMEORIGIN"
|
||||
#</ifmodule>
|
||||
|
||||
<ifmodule mod_headers.c>
|
||||
<FilesMatch "ServiceWorker.js$">
|
||||
Header set Service-Worker-Allowed "/"
|
||||
</FilesMatch>
|
||||
</ifmodule>
|
||||
|
||||
# Php config
|
||||
# This should be removed from here and adjusted in the php.ini file
|
||||
php_value upload_max_filesize 40M
|
||||
php_value post_max_size 40M
|
||||
php_value memory_limit 128M
|
||||
php_value max_input_time 30
|
||||
php_value max_execution_time 30
|
||||
EOT;
|
||||
|
||||
return $htaccess;
|
||||
3
app/web/Install/config.json
Normal file
3
app/web/Install/config.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
|
||||
}
|
||||
0
app/web/Install/db.json
Normal file → Executable file
0
app/web/Install/db.json
Normal file → Executable file
BIN
app/web/Install/db.sqlite
Normal file
BIN
app/web/Install/db.sqlite
Normal file
Binary file not shown.
BIN
app/web/Install/favicon.ico
Executable file
BIN
app/web/Install/favicon.ico
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 361 KiB |
BIN
app/web/Install/img/logo.png
Executable file
BIN
app/web/Install/img/logo.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
19
app/web/Install/index.php
Normal file → Executable file
19
app/web/Install/index.php
Normal file → Executable file
|
|
@ -1,13 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package Install
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://karaka.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
\ob_start();
|
||||
|
||||
//<editor-fold desc="Require/Include">
|
||||
require_once __DIR__ . '/../phpOMS/Autoloader.php';
|
||||
$config = require_once __DIR__ . '/../config.php';
|
||||
//</editor-fold>
|
||||
|
||||
$App = new \Application();
|
||||
echo $App->run();
|
||||
$App = new \Install\WebApplication($config);
|
||||
|
||||
if (\ob_get_level() > 0) {
|
||||
\ob_end_flush();
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
|
|
|||
0
app/web/Install/index.tpl.php
Normal file → Executable file
0
app/web/Install/index.tpl.php
Normal file → Executable file
119
app/web/Install/styles.css
Executable file
119
app/web/Install/styles.css
Executable file
|
|
@ -0,0 +1,119 @@
|
|||
html, body {
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
margin: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
font-family: Open Sans, sans-serif;
|
||||
font-size: 1.0rem;
|
||||
}
|
||||
|
||||
main {
|
||||
height: 100%;
|
||||
width: 600%;
|
||||
|
||||
background: #263729;
|
||||
transition: margin 700ms;
|
||||
}
|
||||
|
||||
.logo {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.page {
|
||||
float: left;
|
||||
background: #2f2f2f;
|
||||
min-height: 100%;
|
||||
width: 16.666%;
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
section {
|
||||
background: #f0f0f0;
|
||||
display: inline-block;
|
||||
margin: 10px 0 10px 0;
|
||||
width: 800px;
|
||||
max-width: 90%;
|
||||
text-align: left;
|
||||
line-height: 1.4rem;
|
||||
font-size: 1.0rem;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
button {
|
||||
border: 1px solid #b7b7b7;
|
||||
padding: 7px 15px 7px 15px;
|
||||
cursor: pointer;
|
||||
background: #dcdcdc;
|
||||
}
|
||||
|
||||
button.next, button.install {
|
||||
float: right;
|
||||
}
|
||||
|
||||
button.prev {
|
||||
float: left;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
section p:last-child {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
background: #e0e0e0;
|
||||
border: 1px solid #ccc;
|
||||
padding: 20px;
|
||||
margin: 0px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
blockquote>p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
th {
|
||||
padding: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 5px 10px 5px 10px;
|
||||
}
|
||||
|
||||
.OK {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.FAILED {
|
||||
color: red;
|
||||
}
|
||||
|
||||
input, select {
|
||||
padding: 5px 10px 5px 10px;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
input:invalid {
|
||||
transition: all 0.5s;
|
||||
border: 1px solid #a5302a;
|
||||
background: #ff7d79;
|
||||
}
|
||||
|
||||
ul, li {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
padding: 5px 0 5px 0;
|
||||
}
|
||||
15
app/web/Models/Account.php
Normal file
15
app/web/Models/Account.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
class Account extends \phpOMS\Account\Account
|
||||
{
|
||||
public int $tries = 0;
|
||||
|
||||
public string $tempPassword = '';
|
||||
|
||||
public array $parents = [];
|
||||
|
||||
public ?\DateTimeImmutable $tempPasswordLimit = null;
|
||||
}
|
||||
39
app/web/Models/AccountCredentialMapper.php
Normal file
39
app/web/Models/AccountCredentialMapper.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
final class AccountCredentialMapper extends AccountMapper
|
||||
{
|
||||
/**
|
||||
* Columns.
|
||||
*
|
||||
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?:array}>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const COLUMNS = [
|
||||
'account_id' => ['name' => 'account_id', 'type' => 'int', 'internal' => 'id'],
|
||||
'account_status' => ['name' => 'account_status', 'type' => 'int', 'internal' => 'status'],
|
||||
'account_type' => ['name' => 'account_type', 'type' => 'int', 'internal' => 'type'],
|
||||
'account_login' => ['name' => 'account_login', 'type' => 'string', 'internal' => 'login', 'autocomplete' => true],
|
||||
'account_name1' => ['name' => 'account_name1', 'type' => 'string', 'internal' => 'name1', 'autocomplete' => true, 'annotations' => ['gdpr' => true]],
|
||||
'account_name2' => ['name' => 'account_name2', 'type' => 'string', 'internal' => 'name2', 'autocomplete' => true, 'annotations' => ['gdpr' => true]],
|
||||
'account_name3' => ['name' => 'account_name3', 'type' => 'string', 'internal' => 'name3', 'autocomplete' => true, 'annotations' => ['gdpr' => true]],
|
||||
'account_password' => ['name' => 'account_password', 'type' => 'string', 'internal' => 'password', 'writeonly' => true],
|
||||
'account_password_temp' => ['name' => 'account_password_temp', 'type' => 'string', 'internal' => 'tempPassword', 'writeonly' => true],
|
||||
'account_password_temp_limit' => ['name' => 'account_password_temp_limit', 'type' => 'DateTimeImmutable', 'internal' => 'tempPasswordLimit'],
|
||||
'account_email' => ['name' => 'account_email', 'type' => 'string', 'internal' => 'email', 'autocomplete' => true, 'annotations' => ['gdpr' => true]],
|
||||
'account_tries' => ['name' => 'account_tries', 'type' => 'int', 'internal' => 'tries'],
|
||||
'account_lactive' => ['name' => 'account_lactive', 'type' => 'DateTime', 'internal' => 'lastActive'],
|
||||
'account_localization' => ['name' => 'account_localization', 'type' => 'int', 'internal' => 'l11n'],
|
||||
'account_created_at' => ['name' => 'account_created_at', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt', 'readonly' => true],
|
||||
];
|
||||
|
||||
/**
|
||||
* Model to use by the mapper.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const MODEL = Account::class;
|
||||
}
|
||||
225
app/web/Models/AccountMapper.php
Normal file
225
app/web/Models/AccountMapper.php
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
use phpOMS\Account\AccountStatus;
|
||||
use phpOMS\Auth\LoginReturnType;
|
||||
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
|
||||
use phpOMS\DataStorage\Database\Query\Builder;
|
||||
|
||||
class AccountMapper extends DataMapperFactory
|
||||
{
|
||||
/**
|
||||
* Columns.
|
||||
*
|
||||
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?:array}>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const COLUMNS = [
|
||||
'account_id' => ['name' => 'account_id', 'type' => 'int', 'internal' => 'id'],
|
||||
'account_status' => ['name' => 'account_status', 'type' => 'int', 'internal' => 'status'],
|
||||
'account_type' => ['name' => 'account_type', 'type' => 'int', 'internal' => 'type'],
|
||||
'account_login' => ['name' => 'account_login', 'type' => 'string', 'internal' => 'login', 'autocomplete' => true],
|
||||
'account_name1' => ['name' => 'account_name1', 'type' => 'string', 'internal' => 'name1', 'autocomplete' => true, 'annotations' => ['gdpr' => true]],
|
||||
'account_name2' => ['name' => 'account_name2', 'type' => 'string', 'internal' => 'name2', 'autocomplete' => true, 'annotations' => ['gdpr' => true]],
|
||||
'account_name3' => ['name' => 'account_name3', 'type' => 'string', 'internal' => 'name3', 'autocomplete' => true, 'annotations' => ['gdpr' => true]],
|
||||
'account_email' => ['name' => 'account_email', 'type' => 'string', 'internal' => 'email', 'autocomplete' => true, 'annotations' => ['gdpr' => true]],
|
||||
'account_tries' => ['name' => 'account_tries', 'type' => 'int', 'internal' => 'tries'],
|
||||
'account_lactive' => ['name' => 'account_lactive', 'type' => 'DateTime', 'internal' => 'lastActive'],
|
||||
'account_localization' => ['name' => 'account_localization', 'type' => 'int', 'internal' => 'l11n'],
|
||||
'account_created_at' => ['name' => 'account_created_at', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt', 'readonly' => true],
|
||||
];
|
||||
|
||||
/**
|
||||
* Has one relation.
|
||||
*
|
||||
* @var array<string, array{mapper:string, external:string, by?:string, column?:string, conditional?:bool}>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const OWNS_ONE = [
|
||||
'l11n' => [
|
||||
'mapper' => LocalizationMapper::class,
|
||||
'external' => 'account_localization',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Has many relation.
|
||||
*
|
||||
* @var array<string, array{mapper:string, table:string, self?:?string, external?:?string, column?:string}>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const HAS_MANY = [
|
||||
'groups' => [
|
||||
'mapper' => GroupMapper::class,
|
||||
'table' => 'account_group',
|
||||
'external' => 'account_group_group',
|
||||
'self' => 'account_group_account',
|
||||
],
|
||||
'parents' => [
|
||||
'mapper' => self::class,
|
||||
'table' => 'account_account_rel',
|
||||
'external' => 'account_account_rel_root',
|
||||
'self' => 'account_account_rel_child',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Model to use by the mapper.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const MODEL = Account::class;
|
||||
|
||||
/**
|
||||
* Primary table.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const TABLE = 'account';
|
||||
|
||||
/**
|
||||
* Primary field name.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const PRIMARYFIELD ='account_id';
|
||||
|
||||
/**
|
||||
* Created at column
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const CREATED_AT = 'account_created_at';
|
||||
|
||||
/**
|
||||
* Get account with permissions
|
||||
*
|
||||
* @param int $id Account id
|
||||
*
|
||||
* @return Account
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function getWithPermissions(int $id) : Account
|
||||
{
|
||||
$account = self::get()->with('groups')->with('groups/permissions')->with('l11n')->where('id', $id)->execute();
|
||||
$groups = \array_keys($account->getGroups());
|
||||
|
||||
/** @var \Modules\Admin\Models\GroupPermission[] $groupPermissions */
|
||||
$groupPermissions = empty($groups)
|
||||
? []
|
||||
: GroupPermissionMapper::getAll()
|
||||
->where('group', \array_keys($account->getGroups()), 'in')
|
||||
->where('element', null)
|
||||
->execute();
|
||||
|
||||
foreach ($groupPermissions as $permission) {
|
||||
$account->addPermissions(\is_array($permission) ? $permission : [$permission]);
|
||||
}
|
||||
|
||||
/** @var \Modules\Admin\Models\AccountPermission[] $accountPermission */
|
||||
$accountPermissions = AccountPermissionMapper::getAll()
|
||||
->where('account', $id)
|
||||
->where('element', null)
|
||||
->execute();
|
||||
|
||||
foreach ($accountPermissions as $permission) {
|
||||
$account->addPermissions(\is_array($permission) ? $permission : [$permission]);
|
||||
}
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login user.
|
||||
*
|
||||
* @param string $login Username
|
||||
* @param string $password Password
|
||||
* @param int $tries Allowed login tries
|
||||
*
|
||||
* @return int Login code
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function login(string $login, string $password, int $tries = 3) : int
|
||||
{
|
||||
if (empty($password)) {
|
||||
return LoginReturnType::WRONG_PASSWORD;
|
||||
}
|
||||
|
||||
try {
|
||||
$result = null;
|
||||
|
||||
$query = new Builder(self::$db);
|
||||
$result = $query->select('account_id', 'account_login', 'account_password', 'account_password_temp', 'account_tries', 'account_status')
|
||||
->from('account')
|
||||
->where('account_login', '=', $login)
|
||||
->execute()
|
||||
?->fetchAll();
|
||||
|
||||
if ($result === null || !isset($result[0])) {
|
||||
return LoginReturnType::WRONG_USERNAME;
|
||||
}
|
||||
|
||||
$result = $result[0];
|
||||
|
||||
if ($result['account_tries'] >= $tries) {
|
||||
return LoginReturnType::WRONG_INPUT_EXCEEDED;
|
||||
}
|
||||
|
||||
if ($result['account_status'] !== AccountStatus::ACTIVE) {
|
||||
return LoginReturnType::INACTIVE;
|
||||
}
|
||||
|
||||
if (empty($result['account_password'])) {
|
||||
return LoginReturnType::EMPTY_PASSWORD;
|
||||
}
|
||||
|
||||
if (\password_verify($password, $result['account_password'] ?? '')) {
|
||||
$query->update('account')
|
||||
->set([
|
||||
'account_lactive' => new \DateTime('now'),
|
||||
'account_tries' => 0,
|
||||
])
|
||||
->where('account_login', '=', $login)
|
||||
->execute();
|
||||
|
||||
return $result['account_id'];
|
||||
}
|
||||
|
||||
if (!empty($result['account_password_temp'])
|
||||
&& $result['account_password_temp_limit'] !== null
|
||||
&& (new \DateTime('now'))->getTimestamp() < (new \DateTime($result['account_password_temp_limit']))->getTimestamp()
|
||||
&& \password_verify($password, $result['account_password_temp'] ?? '')
|
||||
) {
|
||||
$query->update('account')
|
||||
->set([
|
||||
'account_password_temp' => '',
|
||||
'account_lactive' => new \DateTime('now'),
|
||||
'account_tries' => 0,
|
||||
])
|
||||
->where('account_login', '=', $login)
|
||||
->execute();
|
||||
|
||||
return $result['account_id'];
|
||||
}
|
||||
|
||||
$query->update('account')
|
||||
->set([
|
||||
'account_tries' => $result['account_tries'] + 1,
|
||||
])
|
||||
->where('account_login', '=', $login)
|
||||
->execute();
|
||||
|
||||
return LoginReturnType::WRONG_PASSWORD;
|
||||
} catch (\Exception $e) {
|
||||
return LoginReturnType::FAILURE; // @codeCoverageIgnore
|
||||
}
|
||||
}
|
||||
}
|
||||
32
app/web/Models/AccountPermission.php
Normal file
32
app/web/Models/AccountPermission.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Admin\Models;
|
||||
|
||||
use phpOMS\Account\PermissionAbstract;
|
||||
use phpOMS\Account\PermissionType;
|
||||
|
||||
class AccountPermission extends PermissionAbstract
|
||||
{
|
||||
private int $account = 0;
|
||||
|
||||
public function __construct(
|
||||
int $account = 0,
|
||||
int $unit = null,
|
||||
string $app = null,
|
||||
string $module = null,
|
||||
string $from = null,
|
||||
int $category = null,
|
||||
int $element = null,
|
||||
int $component = null,
|
||||
int $permission = PermissionType::NONE
|
||||
) {
|
||||
$this->account = $account;
|
||||
parent::__construct($unit, $app, $module, $from, $category, $element, $component, $permission);
|
||||
}
|
||||
|
||||
public function getAccount() : int
|
||||
{
|
||||
return $this->account;
|
||||
}
|
||||
}
|
||||
56
app/web/Models/AccountPermissionMapper.php
Normal file
56
app/web/Models/AccountPermissionMapper.php
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
|
||||
|
||||
final class AccountPermissionMapper extends DataMapperFactory
|
||||
{
|
||||
/**
|
||||
* Columns.
|
||||
*
|
||||
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?:array}>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const COLUMNS = [
|
||||
'account_permission_id' => ['name' => 'account_permission_id', 'type' => 'int', 'internal' => 'id'],
|
||||
'account_permission_account' => ['name' => 'account_permission_account', 'type' => 'int', 'internal' => 'account'],
|
||||
'account_permission_unit' => ['name' => 'account_permission_unit', 'type' => 'int', 'internal' => 'unit'],
|
||||
'account_permission_app' => ['name' => 'account_permission_app', 'type' => 'string', 'internal' => 'app'],
|
||||
'account_permission_module' => ['name' => 'account_permission_module', 'type' => 'string', 'internal' => 'module'],
|
||||
'account_permission_from' => ['name' => 'account_permission_from', 'type' => 'string', 'internal' => 'from'],
|
||||
'account_permission_category' => ['name' => 'account_permission_category', 'type' => 'int', 'internal' => 'category'],
|
||||
'account_permission_element' => ['name' => 'account_permission_element', 'type' => 'int', 'internal' => 'element'],
|
||||
'account_permission_component' => ['name' => 'account_permission_component', 'type' => 'int', 'internal' => 'component'],
|
||||
'account_permission_hasread' => ['name' => 'account_permission_hasread', 'type' => 'bool', 'internal' => 'hasRead'],
|
||||
'account_permission_hascreate' => ['name' => 'account_permission_hascreate', 'type' => 'bool', 'internal' => 'hasCreate'],
|
||||
'account_permission_hasmodify' => ['name' => 'account_permission_hasmodify', 'type' => 'bool', 'internal' => 'hasModify'],
|
||||
'account_permission_hasdelete' => ['name' => 'account_permission_hasdelete', 'type' => 'bool', 'internal' => 'hasDelete'],
|
||||
'account_permission_haspermission' => ['name' => 'account_permission_haspermission', 'type' => 'bool', 'internal' => 'hasPermission'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Model to use by the mapper.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const MODEL = AccountPermission::class;
|
||||
|
||||
/**
|
||||
* Primary table.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const TABLE = 'account_permission';
|
||||
|
||||
/**
|
||||
* Primary field name.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const PRIMARYFIELD ='account_permission_id';
|
||||
}
|
||||
166
app/web/Models/CoreSettings.php
Executable file
166
app/web/Models/CoreSettings.php
Executable file
|
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
use phpOMS\Config\OptionsTrait;
|
||||
use phpOMS\Config\SettingsInterface;
|
||||
use phpOMS\DataStorage\Cache\CachePool;
|
||||
|
||||
final class CoreSettings implements SettingsInterface
|
||||
{
|
||||
use OptionsTrait;
|
||||
|
||||
protected ?CachePool $cache = null;
|
||||
|
||||
public function get(
|
||||
mixed $ids = null,
|
||||
string|array $names = null,
|
||||
int $app = null,
|
||||
string $module = null,
|
||||
int $group = null,
|
||||
int $account = null
|
||||
) : mixed
|
||||
{
|
||||
$options = [];
|
||||
|
||||
// get by ids
|
||||
if ($ids !== null) {
|
||||
if (!\is_array($ids)) {
|
||||
$ids = [$ids];
|
||||
}
|
||||
|
||||
foreach ($ids as $i => $id) {
|
||||
if ($this->exists($id)) {
|
||||
$options[$id] = $this->getOption($id);
|
||||
unset($ids[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get by names
|
||||
if ($names !== null) {
|
||||
if (!\is_array($names)) {
|
||||
$names = [$names];
|
||||
}
|
||||
|
||||
foreach ($names as $i => $name) {
|
||||
$key = ($name ?? '')
|
||||
. ':' . ($app ?? '')
|
||||
. ':' . ($module ?? '')
|
||||
. ':' . ($group ?? '')
|
||||
. ':' . ($account ?? '');
|
||||
|
||||
$key = \trim($key, ':');
|
||||
|
||||
if ($this->exists($key)) {
|
||||
$options[$key] = $this->getOption($key);
|
||||
unset($names[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// all from cache
|
||||
if (empty($ids) && empty($names)) {
|
||||
return \count($options) > 1 ? $options : \reset($options);
|
||||
}
|
||||
|
||||
/** @var \Model\Setting[] $dbOptions */
|
||||
$dbOptions = SettingMapper::getSettings([
|
||||
'ids' => $ids,
|
||||
'names' => $names,
|
||||
'app' => $app,
|
||||
'module' => $module,
|
||||
'group' => $group,
|
||||
'account' => $account,
|
||||
]);
|
||||
|
||||
// remaining from storage
|
||||
try {
|
||||
foreach ($dbOptions as $option) {
|
||||
$key = ($option->name)
|
||||
. ':' . ($option->app ?? '')
|
||||
. ':' . ($option->module ?? '')
|
||||
. ':' . ($option->group ?? '')
|
||||
. ':' . ($option->account ?? '');
|
||||
|
||||
$key = \trim($key, ':');
|
||||
|
||||
$this->setOption($key, $option, true);
|
||||
|
||||
$options[$key] = $option;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
throw $e; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return \count($options) > 1 ? $options : \reset($options);
|
||||
}
|
||||
|
||||
public function set(array $options, bool $store = false) : void
|
||||
{
|
||||
/** @var array $option */
|
||||
foreach ($options as $option) {
|
||||
$key = ($option['name'] ?? '')
|
||||
. ':' . ($option['app'] ?? '')
|
||||
. ':' . ($option['module'] ?? '')
|
||||
. ':' . ($option['group'] ?? '')
|
||||
. ':' . ($option['account'] ?? '');
|
||||
|
||||
$key = \trim($key, ':');
|
||||
|
||||
$setting = new Setting();
|
||||
$setting->with(
|
||||
$option['id'] ?? 0,
|
||||
$option['name'] ?? '',
|
||||
$option['content'] ?? '',
|
||||
$option['pattern'] ?? '',
|
||||
$option['app'] ?? null,
|
||||
$option['module'] ?? null,
|
||||
$option['group'] ?? null,
|
||||
$option['account'] ?? null,
|
||||
);
|
||||
|
||||
$this->setOption($key, $setting, true);
|
||||
|
||||
if ($store) {
|
||||
SettingMapper::saveSetting($setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function save(array $options = []) : void
|
||||
{
|
||||
$options = empty($options) ? $this->options : $options;
|
||||
|
||||
foreach ($options as $option) {
|
||||
if (\is_array($option)) {
|
||||
$setting = new Setting();
|
||||
$setting->with(
|
||||
$option['id'] ?? 0,
|
||||
$option['name'] ?? '',
|
||||
$option['content'] ?? '',
|
||||
$option['pattern'] ?? '',
|
||||
$option['app'] ?? null,
|
||||
$option['module'] ?? null,
|
||||
$option['group'] ?? null,
|
||||
$option['account'] ?? null,
|
||||
);
|
||||
|
||||
$option = $setting;
|
||||
}
|
||||
|
||||
SettingMapper::saveSetting($option);
|
||||
}
|
||||
}
|
||||
|
||||
public function create(array $options = []) : void
|
||||
{
|
||||
$setting = new Setting();
|
||||
foreach ($options as $column => $option) {
|
||||
$setting->{$column} = $option;
|
||||
}
|
||||
|
||||
SettingMapper::create()->execute($setting);
|
||||
}
|
||||
}
|
||||
27
app/web/Models/Group.php
Executable file
27
app/web/Models/Group.php
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
class Group extends \phpOMS\Account\Group
|
||||
{
|
||||
public \DateTimeImmutable $createdAt;
|
||||
|
||||
public Account $createdBy;
|
||||
|
||||
public string $descriptionRaw = '';
|
||||
|
||||
protected array $accounts = [];
|
||||
|
||||
public function __construct(string $name = '')
|
||||
{
|
||||
$this->createdBy = new NullAccount();
|
||||
$this->createdAt = new \DateTimeImmutable('now');
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getAccounts() : array
|
||||
{
|
||||
return $this->accounts;
|
||||
}
|
||||
}
|
||||
123
app/web/Models/GroupMapper.php
Executable file
123
app/web/Models/GroupMapper.php
Executable file
|
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
|
||||
use phpOMS\DataStorage\Database\Query\Builder;
|
||||
|
||||
final class GroupMapper extends DataMapperFactory
|
||||
{
|
||||
/**
|
||||
* Columns.
|
||||
*
|
||||
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?:array}>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const COLUMNS = [
|
||||
'group_id' => ['name' => 'group_id', 'type' => 'int', 'internal' => 'id'],
|
||||
'group_name' => ['name' => 'group_name', 'type' => 'string', 'internal' => 'name', 'autocomplete' => true],
|
||||
'group_status' => ['name' => 'group_status', 'type' => 'int', 'internal' => 'status'],
|
||||
'group_desc' => ['name' => 'group_desc', 'type' => 'string', 'internal' => 'description'],
|
||||
'group_desc_raw' => ['name' => 'group_desc_raw', 'type' => 'string', 'internal' => 'descriptionRaw'],
|
||||
'group_created' => ['name' => 'group_created', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt', 'readonly' => true],
|
||||
];
|
||||
|
||||
/**
|
||||
* Model to use by the mapper.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const MODEL = Group::class;
|
||||
|
||||
/**
|
||||
* Primary table.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const TABLE = 'group';
|
||||
|
||||
/**
|
||||
* Primary field name.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const PRIMARYFIELD ='group_id';
|
||||
|
||||
/**
|
||||
* Created at column
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const CREATED_AT = 'group_created';
|
||||
|
||||
/**
|
||||
* Has many relation.
|
||||
*
|
||||
* @var array<string, array{mapper:string, table:string, self?:?string, external?:?string, column?:string}>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const HAS_MANY = [
|
||||
'accounts' => [
|
||||
'mapper' => AccountMapper::class,
|
||||
'table' => 'account_group',
|
||||
'external' => 'account_group_account',
|
||||
'self' => 'account_group_group',
|
||||
],
|
||||
'permissions' => [
|
||||
'mapper' => GroupPermissionMapper::class,
|
||||
'table' => 'group_permission',
|
||||
'external' => null,
|
||||
'self' => 'group_permission_group',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Get groups which reference a certain module
|
||||
*
|
||||
* @param string $module Module
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function getPermissionForModule(string $module) : array
|
||||
{
|
||||
$query = self::getQuery();
|
||||
$query->innerJoin(GroupPermissionMapper::TABLE)
|
||||
->on(self::TABLE . '_d1.group_id', '=', GroupPermissionMapper::TABLE . '.group_permission_group')
|
||||
->where(GroupPermissionMapper::TABLE . '.group_permission_module', '=', $module);
|
||||
|
||||
return self::getAll()->execute($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of group members
|
||||
*
|
||||
* @param int $group Group to inspect (0 = all groups)
|
||||
*
|
||||
* @return array<string, int>
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function countMembers(int $group = 0) : array
|
||||
{
|
||||
$query = new Builder(self::$db);
|
||||
$query->select(self::HAS_MANY['accounts']['self'])
|
||||
->select('COUNT(' . self::HAS_MANY['accounts']['external'] . ')')
|
||||
->from(self::HAS_MANY['accounts']['table'])
|
||||
->groupBy(self::HAS_MANY['accounts']['self']);
|
||||
|
||||
if ($group !== 0) {
|
||||
$query->where(self::HAS_MANY['accounts']['self'], '=', $group);
|
||||
}
|
||||
|
||||
$result = $query->execute()?->fetchAll(\PDO::FETCH_KEY_PAIR);
|
||||
|
||||
return $result === null ? [] : $result;
|
||||
}
|
||||
}
|
||||
34
app/web/Models/GroupPermission.php
Normal file
34
app/web/Models/GroupPermission.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
use phpOMS\Account\PermissionAbstract;
|
||||
use phpOMS\Account\PermissionType;
|
||||
|
||||
class GroupPermission extends PermissionAbstract
|
||||
{
|
||||
|
||||
private int $group = 0;
|
||||
|
||||
public function __construct(
|
||||
int $group = 0,
|
||||
int $unit = null,
|
||||
string $app = null,
|
||||
string $module = null,
|
||||
string $from = null,
|
||||
int $category = null,
|
||||
int $element = null,
|
||||
int $component = null,
|
||||
int $permission = PermissionType::NONE
|
||||
) {
|
||||
$this->group = $group;
|
||||
parent::__construct($unit, $app, $module, $from, $category, $element, $component, $permission);
|
||||
}
|
||||
|
||||
public function getGroup() : int
|
||||
{
|
||||
return $this->group;
|
||||
}
|
||||
}
|
||||
57
app/web/Models/GroupPermissionMapper.php
Normal file
57
app/web/Models/GroupPermissionMapper.php
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
|
||||
|
||||
final class GroupPermissionMapper extends DataMapperFactory
|
||||
{
|
||||
/**
|
||||
* Columns.
|
||||
*
|
||||
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?:array}>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const COLUMNS = [
|
||||
'group_permission_id' => ['name' => 'group_permission_id', 'type' => 'int', 'internal' => 'id'],
|
||||
'group_permission_group' => ['name' => 'group_permission_group', 'type' => 'int', 'internal' => 'group'],
|
||||
'group_permission_unit' => ['name' => 'group_permission_unit', 'type' => 'int', 'internal' => 'unit'],
|
||||
'group_permission_app' => ['name' => 'group_permission_app', 'type' => 'string', 'internal' => 'app'],
|
||||
'group_permission_module' => ['name' => 'group_permission_module', 'type' => 'string', 'internal' => 'module'],
|
||||
'group_permission_from' => ['name' => 'group_permission_from', 'type' => 'string', 'internal' => 'from'],
|
||||
'group_permission_category' => ['name' => 'group_permission_category', 'type' => 'int', 'internal' => 'category'],
|
||||
'group_permission_element' => ['name' => 'group_permission_element', 'type' => 'int', 'internal' => 'element'],
|
||||
'group_permission_component' => ['name' => 'group_permission_component', 'type' => 'int', 'internal' => 'component'],
|
||||
'group_permission_hasread' => ['name' => 'group_permission_hasread', 'type' => 'bool', 'internal' => 'hasRead'],
|
||||
'group_permission_hascreate' => ['name' => 'group_permission_hascreate', 'type' => 'bool', 'internal' => 'hasCreate'],
|
||||
'group_permission_hasmodify' => ['name' => 'group_permission_hasmodify', 'type' => 'bool', 'internal' => 'hasModify'],
|
||||
'group_permission_hasdelete' => ['name' => 'group_permission_hasdelete', 'type' => 'bool', 'internal' => 'hasDelete'],
|
||||
'group_permission_haspermission' => ['name' => 'group_permission_haspermission', 'type' => 'bool', 'internal' => 'hasPermission'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Model to use by the mapper.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const MODEL = GroupPermission::class;
|
||||
|
||||
/**
|
||||
* Primary table.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const TABLE = 'group_permission';
|
||||
|
||||
/**
|
||||
* Primary field name.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const PRIMARYFIELD ='group_permission_id';
|
||||
}
|
||||
123
app/web/Models/LocalizationMapper.php
Normal file
123
app/web/Models/LocalizationMapper.php
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
|
||||
use phpOMS\Localization\Defaults\CountryMapper;
|
||||
use phpOMS\Localization\Defaults\CurrencyMapper;
|
||||
use phpOMS\Localization\Defaults\LanguageMapper;
|
||||
use phpOMS\Localization\Localization;
|
||||
|
||||
final class LocalizationMapper extends DataMapperFactory
|
||||
{
|
||||
/**
|
||||
* Columns.
|
||||
*
|
||||
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?:array}>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const COLUMNS = [
|
||||
'l11n_id' => ['name' => 'l11n_id', 'type' => 'int', 'internal' => 'id'],
|
||||
'l11n_country' => ['name' => 'l11n_country', 'type' => 'string', 'internal' => 'country'],
|
||||
'l11n_language' => ['name' => 'l11n_language', 'type' => 'string', 'internal' => 'language'],
|
||||
'l11n_currency' => ['name' => 'l11n_currency', 'type' => 'string', 'internal' => 'currency'],
|
||||
'l11n_currency_format' => ['name' => 'l11n_currency_format', 'type' => 'string', 'internal' => 'currencyFormat'],
|
||||
'l11n_number_thousand' => ['name' => 'l11n_number_thousand', 'type' => 'string', 'internal' => 'thousands'],
|
||||
'l11n_number_decimal' => ['name' => 'l11n_number_decimal', 'type' => 'string', 'internal' => 'decimal'],
|
||||
'l11n_angle' => ['name' => 'l11n_angle', 'type' => 'string', 'internal' => 'angle'],
|
||||
'l11n_temperature' => ['name' => 'l11n_temperature', 'type' => 'string', 'internal' => 'temperature'],
|
||||
'l11n_weight_very_light' => ['name' => 'l11n_weight_very_light', 'type' => 'string', 'internal' => 'weight/very_light'],
|
||||
'l11n_weight_light' => ['name' => 'l11n_weight_light', 'type' => 'string', 'internal' => 'weight/light'],
|
||||
'l11n_weight_medium' => ['name' => 'l11n_weight_medium', 'type' => 'string', 'internal' => 'weight/medium'],
|
||||
'l11n_weight_heavy' => ['name' => 'l11n_weight_heavy', 'type' => 'string', 'internal' => 'weight/heavy'],
|
||||
'l11n_weight_very_heavy' => ['name' => 'l11n_weight_very_heavy', 'type' => 'string', 'internal' => 'weight/very_heavy'],
|
||||
'l11n_speed_very_slow' => ['name' => 'l11n_speed_very_slow', 'type' => 'string', 'internal' => 'speed/very_slow'],
|
||||
'l11n_speed_slow' => ['name' => 'l11n_speed_slow', 'type' => 'string', 'internal' => 'speed/slow'],
|
||||
'l11n_speed_medium' => ['name' => 'l11n_speed_medium', 'type' => 'string', 'internal' => 'speed/medium'],
|
||||
'l11n_speed_fast' => ['name' => 'l11n_speed_fast', 'type' => 'string', 'internal' => 'speed/fast'],
|
||||
'l11n_speed_very_fast' => ['name' => 'l11n_speed_very_fast', 'type' => 'string', 'internal' => 'speed/very_fast'],
|
||||
'l11n_speed_sea' => ['name' => 'l11n_speed_sea', 'type' => 'string', 'internal' => 'speed/sea'],
|
||||
'l11n_length_very_short' => ['name' => 'l11n_length_very_short', 'type' => 'string', 'internal' => 'length/very_short'],
|
||||
'l11n_length_short' => ['name' => 'l11n_length_short', 'type' => 'string', 'internal' => 'length/short'],
|
||||
'l11n_length_medium' => ['name' => 'l11n_length_medium', 'type' => 'string', 'internal' => 'length/medium'],
|
||||
'l11n_length_long' => ['name' => 'l11n_length_long', 'type' => 'string', 'internal' => 'length/long'],
|
||||
'l11n_length_very_long' => ['name' => 'l11n_length_very_long', 'type' => 'string', 'internal' => 'length/very_long'],
|
||||
'l11n_length_sea' => ['name' => 'l11n_length_sea', 'type' => 'string', 'internal' => 'length/sea'],
|
||||
'l11n_area_very_small' => ['name' => 'l11n_area_very_small', 'type' => 'string', 'internal' => 'area/very_small'],
|
||||
'l11n_area_small' => ['name' => 'l11n_area_small', 'type' => 'string', 'internal' => 'area/small'],
|
||||
'l11n_area_medium' => ['name' => 'l11n_area_medium', 'type' => 'string', 'internal' => 'area/medium'],
|
||||
'l11n_area_large' => ['name' => 'l11n_area_large', 'type' => 'string', 'internal' => 'area/large'],
|
||||
'l11n_area_very_large' => ['name' => 'l11n_area_very_large', 'type' => 'string', 'internal' => 'area/very_large'],
|
||||
'l11n_volume_very_small' => ['name' => 'l11n_volume_very_small', 'type' => 'string', 'internal' => 'volume/very_small'],
|
||||
'l11n_volume_small' => ['name' => 'l11n_volume_small', 'type' => 'string', 'internal' => 'volume/small'],
|
||||
'l11n_volume_medium' => ['name' => 'l11n_volume_medium', 'type' => 'string', 'internal' => 'volume/medium'],
|
||||
'l11n_volume_large' => ['name' => 'l11n_volume_large', 'type' => 'string', 'internal' => 'volume/large'],
|
||||
'l11n_volume_very_large' => ['name' => 'l11n_volume_very_large', 'type' => 'string', 'internal' => 'volume/very_large'],
|
||||
'l11n_volume_teaspoon' => ['name' => 'l11n_volume_teaspoon', 'type' => 'string', 'internal' => 'volume/teaspoon'],
|
||||
'l11n_volume_tablespoon' => ['name' => 'l11n_volume_tablespoon', 'type' => 'string', 'internal' => 'volume/tablespoon'],
|
||||
'l11n_volume_glass' => ['name' => 'l11n_volume_glass', 'type' => 'string', 'internal' => 'volume/glass'],
|
||||
'l11n_timezone' => ['name' => 'l11n_timezone', 'type' => 'string', 'internal' => 'timezone'],
|
||||
'l11n_datetime_very_short' => ['name' => 'l11n_datetime_very_short', 'type' => 'string', 'internal' => 'datetime/very_short'],
|
||||
'l11n_datetime_short' => ['name' => 'l11n_datetime_short', 'type' => 'string', 'internal' => 'datetime/short'],
|
||||
'l11n_datetime_medium' => ['name' => 'l11n_datetime_medium', 'type' => 'string', 'internal' => 'datetime/medium'],
|
||||
'l11n_datetime_long' => ['name' => 'l11n_datetime_long', 'type' => 'string', 'internal' => 'datetime/long'],
|
||||
'l11n_datetime_very_long' => ['name' => 'l11n_datetime_very_long', 'type' => 'string', 'internal' => 'datetime/very_long'],
|
||||
'l11n_precision_very_short' => ['name' => 'l11n_precision_very_short', 'type' => 'int', 'internal' => 'precision/very_short'],
|
||||
'l11n_precision_short' => ['name' => 'l11n_precision_short', 'type' => 'int', 'internal' => 'precision/short'],
|
||||
'l11n_precision_medium' => ['name' => 'l11n_precision_medium', 'type' => 'int', 'internal' => 'precision/medium'],
|
||||
'l11n_precision_long' => ['name' => 'l11n_precision_long', 'type' => 'int', 'internal' => 'precision/long'],
|
||||
'l11n_precision_very_long' => ['name' => 'l11n_precision_very_long', 'type' => 'int', 'internal' => 'precision/very_long'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Has one relation.
|
||||
*
|
||||
* @var array<string, array{mapper:string, external:string, by?:string, column?:string, conditional?:bool}>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const OWNS_ONE = [
|
||||
'country' => [
|
||||
'mapper' => CountryMapper::class,
|
||||
'external' => 'l11n_country',
|
||||
'by' => 'code2',
|
||||
'column' => 'code2',
|
||||
],
|
||||
'language' => [
|
||||
'mapper' => LanguageMapper::class,
|
||||
'external' => 'l11n_language',
|
||||
'by' => 'code2',
|
||||
'column' => 'code2',
|
||||
],
|
||||
'currency' => [
|
||||
'mapper' => CurrencyMapper::class,
|
||||
'external' => 'l11n_currency',
|
||||
'by' => 'code',
|
||||
'column' => 'code',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Primary table.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const TABLE = 'l11n';
|
||||
|
||||
/**
|
||||
* Primary field name.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const PRIMARYFIELD ='l11n_id';
|
||||
|
||||
/**
|
||||
* Model to use by the mapper.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const MODEL = Localization::class;
|
||||
}
|
||||
13
app/web/Models/NullAccount.php
Normal file
13
app/web/Models/NullAccount.php
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
final class NullAccount extends Account
|
||||
{
|
||||
public function __construct(int $id = 0)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->id = $id;
|
||||
}
|
||||
}
|
||||
13
app/web/Models/NullSetting.php
Executable file
13
app/web/Models/NullSetting.php
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
final class NullSetting extends Setting
|
||||
{
|
||||
|
||||
public function __construct(int $id = 0)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
}
|
||||
29
app/web/Models/PermissionCategory.php
Normal file
29
app/web/Models/PermissionCategory.php
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
use phpOMS\Stdlib\Base\Enum;
|
||||
|
||||
abstract class PermissionCategory extends Enum
|
||||
{
|
||||
public const SETTINGS = 1;
|
||||
|
||||
public const ACCOUNT = 2;
|
||||
|
||||
public const GROUP = 3;
|
||||
|
||||
public const MODULE = 4;
|
||||
|
||||
public const LOG = 5;
|
||||
|
||||
public const ROUTE = 6;
|
||||
|
||||
public const APP = 7;
|
||||
|
||||
public const ACCOUNT_SETTINGS = 8;
|
||||
|
||||
public const SEARCH = 9;
|
||||
|
||||
public const API = 9;
|
||||
}
|
||||
73
app/web/Models/Setting.php
Executable file
73
app/web/Models/Setting.php
Executable file
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
class Setting
|
||||
{
|
||||
|
||||
protected int $id = 0;
|
||||
|
||||
public string $name = '';
|
||||
|
||||
public string $content = '';
|
||||
|
||||
public string $pattern = '';
|
||||
|
||||
public ?int $app = null;
|
||||
|
||||
public ?string $module = null;
|
||||
|
||||
public ?int $group = null;
|
||||
|
||||
public ?int $account = null;
|
||||
|
||||
public function getId() : int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function with(
|
||||
int $id = 0,
|
||||
string $name = '',
|
||||
string $content = '',
|
||||
string $pattern = '',
|
||||
int $app = null,
|
||||
string $module = null,
|
||||
int $group = null,
|
||||
int $account = null
|
||||
) : self
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->name = $name;
|
||||
$this->content = $content;
|
||||
$this->pattern = $pattern;
|
||||
$this->app = $app;
|
||||
$this->module = $module;
|
||||
$this->group = $group;
|
||||
$this->account = $account;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __construct(
|
||||
int $id = 0,
|
||||
string $name = '',
|
||||
string $content = '',
|
||||
string $pattern = '',
|
||||
int $app = null,
|
||||
string $module = null,
|
||||
int $group = null,
|
||||
int $account = null
|
||||
) {
|
||||
$this->id = $id;
|
||||
$this->name = $name;
|
||||
$this->content = $content;
|
||||
$this->pattern = $pattern;
|
||||
$this->app = $app;
|
||||
$this->module = $module;
|
||||
$this->group = $group;
|
||||
$this->account = $account;
|
||||
}
|
||||
}
|
||||
139
app/web/Models/SettingMapper.php
Executable file
139
app/web/Models/SettingMapper.php
Executable file
|
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
|
||||
use phpOMS\DataStorage\Database\Query\Builder;
|
||||
|
||||
final class SettingMapper extends DataMapperFactory
|
||||
{
|
||||
/**
|
||||
* Columns.
|
||||
*
|
||||
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?:array}>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const COLUMNS = [
|
||||
'settings_id' => ['name' => 'settings_id', 'type' => 'int', 'internal' => 'id'],
|
||||
'settings_name' => ['name' => 'settings_name', 'type' => 'string', 'internal' => 'name'],
|
||||
'settings_content' => ['name' => 'settings_content', 'type' => 'string', 'internal' => 'content'],
|
||||
'settings_pattern' => ['name' => 'settings_pattern', 'type' => 'string', 'internal' => 'pattern'],
|
||||
'settings_app' => ['name' => 'settings_app', 'type' => 'int', 'internal' => 'app'],
|
||||
'settings_module' => ['name' => 'settings_module', 'type' => 'string', 'internal' => 'module'],
|
||||
'settings_group' => ['name' => 'settings_group', 'type' => 'int', 'internal' => 'group'],
|
||||
'settings_account' => ['name' => 'settings_account', 'type' => 'int', 'internal' => 'account'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Model to use by the mapper.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const MODEL = Setting::class;
|
||||
|
||||
/**
|
||||
* Primary table.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const TABLE = 'settings';
|
||||
|
||||
/**
|
||||
* Primary field name.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const PRIMARYFIELD ='settings_id';
|
||||
|
||||
/**
|
||||
* Save setting / option to database
|
||||
*
|
||||
* @param Setting $option Option / setting
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function saveSetting(Setting $option) : void
|
||||
{
|
||||
$query = new Builder(self::$db);
|
||||
$query->update(self::TABLE)
|
||||
->set(['settings_content' => $option->content]);
|
||||
|
||||
if (!empty($option->getId())) {
|
||||
$query->where('settings_id', '=', $option->getId());
|
||||
}
|
||||
|
||||
if (!empty($option->name)) {
|
||||
$query->andWhere('settings_name', '=', $option->name);
|
||||
}
|
||||
|
||||
if (!empty($option->app)) {
|
||||
$query->andWhere('settings_app', '=', $option->app);
|
||||
}
|
||||
|
||||
if (!empty($option->module)) {
|
||||
$query->andWhere('settings_module', '=', $option->module);
|
||||
}
|
||||
|
||||
if (!empty($option->group)) {
|
||||
$query->andWhere('settings_group', '=', $option->group);
|
||||
}
|
||||
|
||||
if (!empty($option->account)) {
|
||||
$query->andWhere('settings_account', '=', $option->account);
|
||||
}
|
||||
|
||||
$sth = self::$db->con->prepare($query->toSql());
|
||||
if ($sth === false) {
|
||||
return; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$sth->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get setting / option from database
|
||||
*
|
||||
* @param array $where Where conditions
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function getSettings(array $where) : array
|
||||
{
|
||||
$query = self::getQuery();
|
||||
|
||||
if (!empty($where['ids'])) {
|
||||
$query->where('settings_id', 'in', $where['ids']);
|
||||
}
|
||||
|
||||
if (!empty($where['names'])) {
|
||||
$query->andWhere('settings_name', 'in', $where['names']);
|
||||
}
|
||||
|
||||
if (!empty($where['app'])) {
|
||||
$query->andWhere('settings_app', '=', $where['app']);
|
||||
}
|
||||
|
||||
if (!empty($where['module'])) {
|
||||
$query->andWhere('settings_module', '=', $where['module']);
|
||||
}
|
||||
|
||||
if (!empty($where['group'])) {
|
||||
$query->andWhere('settings_group', '=', $where['group']);
|
||||
}
|
||||
|
||||
if (!empty($where['account'])) {
|
||||
$query->andWhere('settings_account', '=', $where['account']);
|
||||
}
|
||||
|
||||
return self::getAll()->execute($query);
|
||||
}
|
||||
}
|
||||
70
app/web/Models/SettingsEnum.php
Normal file
70
app/web/Models/SettingsEnum.php
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Models;
|
||||
|
||||
use phpOMS\Stdlib\Base\Enum;
|
||||
|
||||
abstract class SettingsEnum extends Enum
|
||||
{
|
||||
/* Logging settings */
|
||||
public const PASSWORD_PATTERN = '1000000001';
|
||||
|
||||
public const LOGIN_TIMEOUT = '1000000002';
|
||||
|
||||
public const PASSWORD_INTERVAL = '1000000003';
|
||||
|
||||
public const PASSWORD_HISTORY = '1000000004';
|
||||
|
||||
public const LOGIN_TRIES = '1000000005';
|
||||
|
||||
public const LOGGING_STATUS = '1000000006';
|
||||
|
||||
public const LOGGING_PATH = '1000000007';
|
||||
|
||||
/* Organization settings */
|
||||
public const DEFAULT_ORGANIZATION = '1000000009';
|
||||
|
||||
/* Login settings */
|
||||
public const LOGIN_FORGOTTEN_COUNT = '1000000010';
|
||||
|
||||
public const LOGIN_FORGOTTEN_DATE = '1000000011';
|
||||
|
||||
public const LOGIN_FORGOTTEN_TOKEN = '1000000012';
|
||||
|
||||
public const LOGIN_STATUS = '1000000013';
|
||||
|
||||
/* Localization settings */
|
||||
public const DEFAULT_LOCALIZATION = '1000000014';
|
||||
|
||||
/* Mail settings */
|
||||
public const MAIL_SERVER_ADDR = '1000000015';
|
||||
|
||||
public const MAIL_SERVER_TYPE = '1000000016';
|
||||
|
||||
public const MAIL_SERVER_USER = '1000000017';
|
||||
|
||||
public const MAIL_SERVER_PASS = '1000000018';
|
||||
|
||||
public const MAIL_SERVER_CERT = '1000000019';
|
||||
|
||||
public const MAIL_SERVER_KEY = '1000000020';
|
||||
|
||||
public const MAIL_SERVER_KEYPASS = '1000000021';
|
||||
|
||||
public const MAIL_SERVER_TLS = '1000000022';
|
||||
|
||||
/* Cli settings */
|
||||
public const CLI_ACTIVE = '1000000023';
|
||||
|
||||
/* Global default templates */
|
||||
public const DEFAULT_PDF_EXPORT_TEMPLATE = '1000000024';
|
||||
|
||||
public const DEFAULT_CSV_EXPORT_TEMPLATE = '1000000025';
|
||||
|
||||
public const DEFAULT_EXCEL_EXPORT_TEMPLATE = '1000000026';
|
||||
|
||||
public const DEFAULT_WORD_EXPORT_TEMPLATE = '1000000027';
|
||||
|
||||
public const DEFAULT_EMAIL_EXPORT_TEMPLATE = '1000000028';
|
||||
}
|
||||
212
app/web/WebApplication.php
Normal file
212
app/web/WebApplication.php
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
use phpOMS\Autoloader;
|
||||
use phpOMS\Application\ApplicationAbstract;
|
||||
use phpOMS\Localization\ISO639x1Enum;
|
||||
use phpOMS\Localization\Localization;
|
||||
use phpOMS\Log\FileLogger;
|
||||
use phpOMS\Message\Http\HttpRequest;
|
||||
use phpOMS\Message\Http\HttpResponse;
|
||||
use phpOMS\System\File\PathException;
|
||||
use phpOMS\Uri\HttpUri;
|
||||
use phpOMS\Uri\UriFactory;
|
||||
|
||||
class WebApplication extends ApplicationAbstract
|
||||
{
|
||||
public function __construct(array $config)
|
||||
{
|
||||
$response = null;
|
||||
$sub = null;
|
||||
|
||||
try {
|
||||
$this->setupHandlers();
|
||||
|
||||
$this->logger = FileLogger::getInstance($config['log']['file']['path'], false);
|
||||
|
||||
UriFactory::setQuery('/prefix', '');
|
||||
UriFactory::setQuery('/api', 'api/');
|
||||
$applicationName = $this->getApplicationName(HttpUri::fromCurrent(), $config['app'], $config['page']['root']);
|
||||
$request = $this->initRequest($config['page']['root'], $config['app']);
|
||||
$response = $this->initResponse($request, $config);
|
||||
|
||||
$this->theme = $this->getApplicationTheme($request, $config['app']['domains']);
|
||||
|
||||
$app = '\Applications\\' . $applicationName . '\Application';
|
||||
$sub = new $app($this, $config);
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->critical(FileLogger::MSG_FULL, [
|
||||
'message' => $e->getMessage(),
|
||||
'line' => __LINE__, ]);
|
||||
$sub = new \Applications\E500\Application($this, $config);
|
||||
} finally {
|
||||
if ($sub === null) {
|
||||
$sub = new \Applications\E500\Application($this, $config);
|
||||
}
|
||||
|
||||
if ($response === null) {
|
||||
$response = new HttpResponse();
|
||||
}
|
||||
|
||||
$request ??= HttpRequest::createFromSuperglobals();
|
||||
$sub->run($request, $response);
|
||||
|
||||
$body = $response->getBody(true);
|
||||
|
||||
if (isset($this->sessionManager)) {
|
||||
$this->sessionManager->save();
|
||||
}
|
||||
|
||||
if (!$response->header->isLocked()) {
|
||||
$response->header->push();
|
||||
}
|
||||
|
||||
if (isset($this->sessionManager)) {
|
||||
$this->sessionManager->lock();
|
||||
}
|
||||
|
||||
echo $body;
|
||||
}
|
||||
}
|
||||
|
||||
private function setupHandlers() : void
|
||||
{
|
||||
\set_exception_handler(['\phpOMS\UnhandledHandler', 'exceptionHandler']);
|
||||
\set_error_handler(['\phpOMS\UnhandledHandler', 'errorHandler']);
|
||||
\register_shutdown_function(['\phpOMS\UnhandledHandler', 'shutdownHandler']);
|
||||
\mb_internal_encoding('UTF-8');
|
||||
}
|
||||
|
||||
private function initRequest(string $rootPath, array $config) : HttpRequest
|
||||
{
|
||||
$request = HttpRequest::createFromSuperglobals();
|
||||
$subDirDepth = \substr_count($rootPath, '/') - 1;
|
||||
|
||||
$defaultLang = $config['domains'][$request->uri->host]['lang'] ?? $config['default']['lang'];
|
||||
$uriLang = \strtolower($request->uri->getPathElement($subDirDepth + 0));
|
||||
$requestLang = $request->getRequestLanguage();
|
||||
$langCode = ISO639x1Enum::isValidValue($uriLang)
|
||||
? $uriLang
|
||||
: (ISO639x1Enum::isValidValue($requestLang)
|
||||
? $requestLang
|
||||
: $defaultLang
|
||||
);
|
||||
|
||||
$pathOffset = $subDirDepth
|
||||
+ (ISO639x1Enum::isValidValue($uriLang)
|
||||
? 1 + ($this->getApplicationNameFromString($request->uri->getPathElement($subDirDepth + 1)) !== 'E500' ? 1 : 0)
|
||||
: 0 + ($this->getApplicationNameFromString($request->uri->getPathElement($subDirDepth + 0)) !== 'E500' ? 1 : 0)
|
||||
);
|
||||
|
||||
$request->createRequestHashs($pathOffset);
|
||||
$request->uri->setRootPath($rootPath);
|
||||
$request->uri->setPathOffset($pathOffset);
|
||||
UriFactory::setupUriBuilder($request->uri);
|
||||
|
||||
$request->header->l11n->loadFromLanguage($langCode, \explode('_', $request->getLocale())[1] ?? '*');
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
private function initResponse(HttpRequest $request, array $config) : HttpResponse
|
||||
{
|
||||
$response = new HttpResponse(new Localization());
|
||||
$response->header->set('content-type', 'text/html; charset=utf-8');
|
||||
$response->header->set('x-xss-protection', '1; mode=block');
|
||||
$response->header->set('x-content-type-options', 'nosniff');
|
||||
$response->header->set('x-frame-options', 'SAMEORIGIN');
|
||||
$response->header->set('referrer-policy', 'same-origin');
|
||||
|
||||
if ($request->isHttps()) {
|
||||
$response->header->set('strict-transport-security', 'max-age=31536000');
|
||||
}
|
||||
|
||||
$defaultLang = $config['app']['domains'][$request->uri->host]['lang'] ?? $config['app']['default']['lang'];
|
||||
$uriLang = \strtolower($request->uri->getPathElement(0));
|
||||
$requestLang = $request->getLanguage();
|
||||
$langCode = ISO639x1Enum::isValidValue($requestLang) && \in_array($requestLang, $config['language'])
|
||||
? $requestLang
|
||||
: (ISO639x1Enum::isValidValue($uriLang) && \in_array($uriLang, $config['language'])
|
||||
? $uriLang
|
||||
: $defaultLang
|
||||
);
|
||||
|
||||
$response->header->l11n->loadFromLanguage($langCode, \explode('_', $request->getLocale())[1] ?? '*');
|
||||
UriFactory::setQuery('/lang', $request->getLanguage());
|
||||
|
||||
if (ISO639x1Enum::isValidValue($uriLang)) {
|
||||
UriFactory::setQuery('/prefix', $uriLang . '/' . (empty(UriFactory::getQuery('/prefix')) ? '' : UriFactory::getQuery('/prefix')));
|
||||
UriFactory::setQuery('/api', $uriLang . '/' . (empty(UriFactory::getQuery('/api')) ? '' : UriFactory::getQuery('/api')));
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function getApplicationName(HttpUri $uri, array $config, string $rootPath) : string
|
||||
{
|
||||
$subDirDepth = \substr_count($rootPath, '/') - 1;
|
||||
|
||||
// check subdomain
|
||||
$appName = $uri->getSubdomain();
|
||||
$appName = $this->getApplicationNameFromString($appName);
|
||||
|
||||
if ($appName !== 'E500') {
|
||||
return $appName;
|
||||
}
|
||||
|
||||
// check uri path 0 (no language is defined)
|
||||
$appName = $uri->getPathElement($subDirDepth + 0);
|
||||
$appName = $this->getApplicationNameFromString($appName);
|
||||
|
||||
if ($appName !== 'E500') {
|
||||
UriFactory::setQuery('/prefix', (empty(UriFactory::getQuery('/prefix')) ? '' : UriFactory::getQuery('/prefix') . '/') . $uri->getPathElement($subDirDepth + 1) . '/');
|
||||
|
||||
return $appName;
|
||||
}
|
||||
|
||||
// check uri path 1 (language is defined)
|
||||
if (ISO639x1Enum::isValidValue($uri->getPathElement($subDirDepth + 0))) {
|
||||
$appName = $uri->getPathElement($subDirDepth + 1);
|
||||
$appName = $this->getApplicationNameFromString($appName);
|
||||
|
||||
if ($appName !== 'E500') {
|
||||
UriFactory::setQuery('/prefix', (empty(UriFactory::getQuery('/prefix')) ? '' : UriFactory::getQuery('/prefix') . '/') . $uri->getPathElement($subDirDepth + 1) . '/');
|
||||
|
||||
return $appName;
|
||||
}
|
||||
}
|
||||
|
||||
// check config
|
||||
$appName = $config['domains'][$uri->host]['app'] ?? $config['default']['app'];
|
||||
|
||||
return $this->getApplicationNameFromString($appName);
|
||||
}
|
||||
|
||||
private function getApplicationNameFromString(string $app) : string
|
||||
{
|
||||
$applicationName = \ucfirst(\strtolower($app));
|
||||
|
||||
if (empty($applicationName) || !Autoloader::exists('\\Applications\\' . $applicationName . '\\Application')) {
|
||||
$applicationName = 'E500';
|
||||
}
|
||||
|
||||
return $applicationName;
|
||||
}
|
||||
|
||||
private function getApplicationTheme(HttpRequest $request, array $config) : string
|
||||
{
|
||||
return $config[$request->uri->host]['theme'] ?? 'Backend';
|
||||
}
|
||||
|
||||
public function loadLanguageFromPath(string $language, string $path) : void
|
||||
{
|
||||
/* Load theme language */
|
||||
if (($absPath = \realpath($path)) === false) {
|
||||
throw new PathException($path);
|
||||
}
|
||||
|
||||
/** @noinspection PhpIncludeInspection */
|
||||
$themeLanguage = include $absPath;
|
||||
$this->l11nManager->loadLanguage($language, '0', $themeLanguage);
|
||||
}
|
||||
}
|
||||
|
|
@ -5,8 +5,9 @@ declare(strict_types=1);
|
|||
|
||||
require_once __DIR__ . '/phpOMS/Autoloader.php';
|
||||
|
||||
$App = new \Application();
|
||||
echo $App->run();
|
||||
$config = require_once __DIR__ . '/config.php';
|
||||
|
||||
$App = new \WebApplication($config);
|
||||
|
||||
if (\ob_get_level() > 0) {
|
||||
\ob_end_flush();
|
||||
|
|
|
|||
1
app/web/jsOMS
Submodule
1
app/web/jsOMS
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit e3aef7338ab615b8520f4fcbe82572fbf71b0934
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package Web\Backend
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://karaka.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
use phpOMS\Uri\UriFactory;
|
||||
|
||||
/** @var Web\Backend\BackendView $this */
|
||||
$nav = $this->getData('nav');
|
||||
|
||||
$nav->setTemplate('/Modules/Navigation/Theme/Backend/top');
|
||||
$top = $nav->render();
|
||||
|
||||
$nav->setTemplate('/Modules/Navigation/Theme/Backend/side');
|
||||
$side = $nav->render();
|
||||
|
||||
/** @var phpOMS\Model\Html\Head $head */
|
||||
$head = $this->getData('head');
|
||||
|
||||
/** @var array $dispatch */
|
||||
$dispatch = $this->getData('dispatch') ?? [];
|
||||
?>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="<?= $this->printHtml($this->response->getLanguage()); ?>">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#343a40">
|
||||
<meta name="msapplication-navbutton-color" content="#343a40">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="#343a40">
|
||||
<meta name="description" content="<?= $this->getHtml(':meta', '0', '0'); ?>">
|
||||
<base href="<?= UriFactory::build('{/base}'); ?>/">
|
||||
|
||||
<?= $head->meta->render(); ?>
|
||||
|
||||
<link rel="manifest" href="<?= UriFactory::build('Web/Backend/manifest.json'); ?>">
|
||||
<link rel="manifest" href="<?= UriFactory::build('Web/Backend/manifest.webmanifest'); ?>">
|
||||
<link rel="shortcut icon" href="<?= UriFactory::build('Web/Backend/img/favicon.ico?v=1.0.0'); ?>" type="image/x-icon">
|
||||
|
||||
<title><?= $this->printHtml($head->title); ?></title>
|
||||
|
||||
<?= $head->renderAssets(); ?>
|
||||
|
||||
<style><?= $head->renderStyle(); ?></style>
|
||||
<script><?= $head->renderScript(); ?></script>
|
||||
</head>
|
||||
<body>
|
||||
<?php
|
||||
$c = 0;
|
||||
foreach ($dispatch as $view) {
|
||||
if (!($view instanceof \phpOMS\Views\NullView)
|
||||
&& $view instanceof \phpOMS\Contract\RenderableInterface
|
||||
) {
|
||||
++$c;
|
||||
echo $view->render();
|
||||
}
|
||||
}
|
||||
|
||||
if ($c === 0) {
|
||||
echo '<div class="emptyPage"></div>';
|
||||
}
|
||||
?>
|
||||
<?= $head->renderAssetsLate(); ?>
|
||||
Loading…
Reference in New Issue
Block a user