mirror of
https://github.com/Karaka-Management/oms-OnlineResourceWatcher.git
synced 2026-02-17 00:18: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"]
|
[submodule "app/web/cssOMS"]
|
||||||
path = app/web/cssOMS
|
path = app/web/cssOMS
|
||||||
url = https://github.com/Karaka-Management/cssOMS.git
|
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");
|
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)
|
void checkResources(int argc, char **argv)
|
||||||
{
|
{
|
||||||
unsigned long long resourceId = atoll(Utils::ArrayUtils::get_arg("-r", argv, argc));
|
unsigned long long resourceId = atoll(Utils::ArrayUtils::get_arg("-r", argv, argc));
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,13 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "cOMS/Utils/Parser/Json.h"
|
#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"
|
#include "../Models/InstallType.h"
|
||||||
|
|
||||||
|
|
@ -21,26 +26,92 @@ namespace Controller {
|
||||||
namespace InstallController {
|
namespace InstallController {
|
||||||
void installApplication(int argc, char **argv)
|
void installApplication(int argc, char **argv)
|
||||||
{
|
{
|
||||||
// @todo handle install
|
Models::InstallType type = (Models::InstallType) atoi(Utils::ArrayUtils::get_arg("-t", argv, argc));
|
||||||
// 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
|
|
||||||
|
|
||||||
|
int status = 0;
|
||||||
|
if (type == Models::InstallType::WEB) {
|
||||||
|
status = installWeb();
|
||||||
} else {
|
} else {
|
||||||
|
status = installLocal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// create config file
|
if (status == 0) {
|
||||||
nlohmann::json config;
|
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()
|
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;
|
} Account;
|
||||||
|
|
||||||
inline
|
inline
|
||||||
void freeAccount(Account *obj)
|
void free_Account(Account *obj)
|
||||||
{
|
{
|
||||||
if (obj->email != NULL) {
|
if (obj->email != NULL) {
|
||||||
free(obj->email);
|
free(obj->email);
|
||||||
|
|
@ -47,12 +47,11 @@ namespace Models {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj->org != NULL) {
|
if (obj->org != NULL) {
|
||||||
freeOrganization(obj->org);
|
free_Organization(obj->org);
|
||||||
|
free(obj->org);
|
||||||
|
|
||||||
obj->org = NULL;
|
obj->org = NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(obj);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@
|
||||||
|
|
||||||
namespace Models {
|
namespace Models {
|
||||||
typedef enum {
|
typedef enum {
|
||||||
WEB = 0,
|
WEB = 1,
|
||||||
LOCAL = 1
|
LOCAL = 2
|
||||||
} InstallType;
|
} InstallType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,8 @@ namespace Models {
|
||||||
} Organization;
|
} Organization;
|
||||||
|
|
||||||
inline
|
inline
|
||||||
void freeOrganization(Organization *obj)
|
void free_Organization(Organization *obj)
|
||||||
{
|
{
|
||||||
free(obj);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ namespace Models {
|
||||||
} Resource;
|
} Resource;
|
||||||
|
|
||||||
inline
|
inline
|
||||||
void freeResource(Resource *obj)
|
void free_Resource(Resource *obj)
|
||||||
{
|
{
|
||||||
if (obj->uri != NULL) {
|
if (obj->uri != NULL) {
|
||||||
free(obj->uri);
|
free(obj->uri);
|
||||||
|
|
@ -70,18 +70,20 @@ namespace Models {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj->info != NULL) {
|
if (obj->info != NULL) {
|
||||||
|
free_ResourceInfo(obj->info);
|
||||||
free(obj->info);
|
free(obj->info);
|
||||||
|
|
||||||
obj->info = NULL;
|
obj->info = NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj->org != NULL) {
|
if (obj->org != NULL) {
|
||||||
freeOrganization(obj->org);
|
free_Organization(obj->org);
|
||||||
|
free(obj->org);
|
||||||
|
|
||||||
obj->org = NULL;
|
obj->org = NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(obj);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ namespace Models {
|
||||||
} ResourceInfo;
|
} ResourceInfo;
|
||||||
|
|
||||||
inline
|
inline
|
||||||
void freeResourceInfo(ResourceInfo *obj)
|
void free_ResourceInfo(ResourceInfo *obj)
|
||||||
{
|
{
|
||||||
if (obj->mail != NULL) {
|
if (obj->mail != NULL) {
|
||||||
free(obj->mail);
|
free(obj->mail);
|
||||||
|
|
@ -36,11 +36,11 @@ namespace Models {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj->account != NULL) {
|
if (obj->account != NULL) {
|
||||||
freeAccount(obj->account);
|
free_Account(obj->account);
|
||||||
|
free(obj->account);
|
||||||
|
|
||||||
obj->account = NULL;
|
obj->account = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(obj);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ typedef void (*Fptr)(int, char **);
|
||||||
|
|
||||||
Stdlib::HashTable::ht *generate_routes()
|
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) {
|
if (table == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,6 @@ sudo apt-get install sqlite3 libsqlite3-dev
|
||||||
sudo apt install default-libmysqlclient-dev
|
sudo apt install default-libmysqlclient-dev
|
||||||
sudo apt-get install libxml2-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 <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "cOMS/Utils/ApplicationUtils.h"
|
||||||
|
#include "DataStorage/Database/Connection/ConnectionAbstract.h"
|
||||||
#include "cOMS/Utils/Parser/Json.h"
|
#include "cOMS/Utils/Parser/Json.h"
|
||||||
#include "Stdlib/HashTable.h"
|
#include "Stdlib/HashTable.h"
|
||||||
|
|
||||||
|
|
@ -20,47 +22,30 @@
|
||||||
#define OMS_DEMO false
|
#define OMS_DEMO false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void parseConfigFile()
|
typedef struct {
|
||||||
{
|
DataStorage::Database::ConnectionAbstract *db;
|
||||||
FILE *fp = fopen("config.json", "r");
|
nlohmann::json config;
|
||||||
|
} App;
|
||||||
|
|
||||||
nlohmann::json config = nlohmann::json::parse(fp);
|
App app;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
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?
|
// Set program path as cwd
|
||||||
// no? install
|
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
|
// Load config
|
||||||
if (!Utils::FileUtils::file_exists("config.json")) {
|
if (!Utils::FileUtils::file_exists("config.json")) {
|
||||||
printf("No config file available.");
|
Controller::ApiController::notInstalled(argc, argv);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -77,6 +62,17 @@ int main(int argc, char **argv)
|
||||||
(*ptr)(argc, argv);
|
(*ptr)(argc, argv);
|
||||||
|
|
||||||
Stdlib::HashTable::free_table(routes);
|
Stdlib::HashTable::free_table(routes);
|
||||||
|
free(routes);
|
||||||
|
|
||||||
free(arg);
|
free(arg);
|
||||||
arg = NULL;
|
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
|
<?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);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
\ob_start();
|
\ob_start();
|
||||||
|
|
||||||
|
//<editor-fold desc="Require/Include">
|
||||||
require_once __DIR__ . '/../phpOMS/Autoloader.php';
|
require_once __DIR__ . '/../phpOMS/Autoloader.php';
|
||||||
|
$config = require_once __DIR__ . '/../config.php';
|
||||||
|
//</editor-fold>
|
||||||
|
|
||||||
$App = new \Application();
|
$App = new \Install\WebApplication($config);
|
||||||
echo $App->run();
|
|
||||||
|
|
||||||
if (\ob_get_level() > 0) {
|
if (\ob_get_level() > 0) {
|
||||||
\ob_end_flush();
|
\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';
|
require_once __DIR__ . '/phpOMS/Autoloader.php';
|
||||||
|
|
||||||
$App = new \Application();
|
$config = require_once __DIR__ . '/config.php';
|
||||||
echo $App->run();
|
|
||||||
|
$App = new \WebApplication($config);
|
||||||
|
|
||||||
if (\ob_get_level() > 0) {
|
if (\ob_get_level() > 0) {
|
||||||
\ob_end_flush();
|
\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