Compare commits

...

33 Commits

Author SHA1 Message Date
engineerTrooper 6523e77742 VENOM: Entity fixed JSON
EntityManger added return value
EntityManager added getFirst
Fixed Some Admin shit :)
2021-01-04 22:24:32 +01:00
Maurice Grönwoldt eb6770204a VENOM-10: Moved to new Module Structure
Fixed File-Endings
Added Entity-System
2021-01-03 16:59:11 +01:00
engineerTrooper 32a78ed1b9 VENOM: Hardcode WIP (versustunez) 2020-12-22 18:07:13 +01:00
engineerTrooper 7b90160c48 VENOM-10: Fix Hamburger 2020-12-16 17:05:38 +01:00
engineerTrooper 6f93d0d4dd VENOM-10: Added Missing Css 2020-12-16 16:35:12 +01:00
engineerTrooper 3c9be5efba VENOM: fixed Routing to class SeoController 2020-12-16 16:16:54 +01:00
engineerTrooper 430681d84f VENOM-10: fixed menu symbol to hamburger symbol (visible in tablet and mobile view) 2020-12-16 16:16:10 +01:00
engineerTrooper 196ff0b1f1 VENOM: Fix Router cannot find Route if Trailing Slash is existing (VersusTuneZ)
FIX Typos
Change Folder
WIP
2020-12-13 01:26:02 +01:00
Maurice Grönwoldt 85549fbd43 VENOM-10: Clean Up Code 2020-12-08 18:37:59 +01:00
engineerTrooper 7d540d809a VENOM-2: added app-container, added nav-button at mobile and tablets screens 2020-12-08 16:41:59 +01:00
engineerTrooper 147cd09d13 VENOM-2: deleted class overview 2020-12-08 16:41:23 +01:00
engineerTrooper 6bac93205c VENOM-2: added v-input parameters 2020-12-08 16:40:23 +01:00
engineerTrooper e29163165f VENOM-2: changed code to V-Utils via VTepl (50%) -> result: minified code 2020-12-08 16:38:43 +01:00
engineerTrooper aacf885c56 VENOM-2: changed code to V-Utils via VTepl -> result: minified code, added classes and flexbox, fixed data display at v-table 2020-12-08 16:38:01 +01:00
engineerTrooper 1e4e71ad9c VENOM-10: added new function isMobileDevice 2020-12-08 16:33:34 +01:00
engineerTrooper 2d9fbc3b99 VENOM-2: update minimized files 2020-12-08 16:32:59 +01:00
Maurice Grönwoldt 147189288f VENOM-10: Moved Modules to Own File to avoid User have to add it!
FIXED composer.json
2020-12-06 12:30:12 +01:00
engineerTrooper f9dd03193e VENOM-10: added files x.tpl, x.php Modules 2020-12-03 17:58:36 +01:00
Maurice Grönwoldt 3d92f5347a VENOM: FIX PHP8! 2020-11-30 09:01:31 +01:00
Maurice Grönwoldt 5c44d50989 VENOM-10: WIP 2020-11-18 17:50:01 +01:00
Maurice Grönwoldt 8d246aa381 Fix missing TYPE on fucking INPUTS 2020-11-17 22:37:33 +01:00
Maurice Grönwoldt a34201ffc2 Fix Some errors
Fix Input-Fields (not all fixed <3 pls dome)
2020-11-17 22:34:04 +01:00
engineerTrooper f7b7b6c956 VENOM-10: added textarea with style and style correction on v-selects 2020-11-17 15:13:58 +01:00
engineerTrooper 9519236662 VENOM-10: added, fake tables with display:grid. create v-table as html dom element 2020-11-15 19:19:23 +01:00
engineerTrooper 162cc4b0a4 VENOM-10 : added design (first step) 2020-11-01 18:59:05 +01:00
Maurice Grönwoldt 8b87c7d2f7 VENOM-2: do new login <3 2020-10-21 17:14:08 +02:00
Maurice Grönwoldt 597be3ce2e added logo (pls move to theme folder!)
added svg logo from webinterface
2020-10-06 16:40:10 +02:00
Maurice Grönwoldt 0baed1a7fc VENOM-2: Fixed Login, fixed missing scripts.min.js, 2020-10-05 20:38:36 +02:00
engineerTrooper a2931d93f7 VENOM-2 : WIP 2020-10-05 20:02:43 +02:00
Maurice Grönwoldt c7984873c0 fixed login
added example login
2020-09-25 22:33:35 +02:00
Maurice Grönwoldt f00bdc99ec fixed security login 2020-09-25 21:51:39 +02:00
Maurice Grönwoldt 2db5aa8693 cherry-picked changes Meta-Generator from engineer-trooper 2020-09-25 21:39:05 +02:00
Maurice Grönwoldt f7fa124535 WIP 2020-09-25 21:33:54 +02:00
100 changed files with 3609 additions and 258 deletions

5
.gitignore vendored
View File

@ -466,3 +466,8 @@ conf/modules.inc.php
conf/routers.inc.php
conf/lang.inc.php
logs/Exception.log
z_dome/
composer.lock
adminer.php

View File

@ -1,18 +1,18 @@
<?php
use Venom\Core\Config;
use Venom\Core\DatabaseHandler;
use Venom\Core\Database\Database;
$config = Config::getInstance();
$config->setVersion(1.0);
$config->setDatabase([
DatabaseHandler::DB_TYPE => 'mysql', //please change only if you know what you're doing! this can break a lot.
DatabaseHandler::DB_HOST => '127.0.0.1',
DatabaseHandler::DB_PORT => '3306', //default port is 3306
DatabaseHandler::DB_USER => 'venom',
DatabaseHandler::DB_PASSWORD => 'venomPassword',
DatabaseHandler::DB_DB => 'venomCMS',
DatabaseHandler::DB_EXTRA => '' // need to start with ';'
Database::DB_TYPE => 'mysql', //please change only if you know what you're doing! this can break a lot.
Database::DB_HOST => '127.0.0.1',
Database::DB_PORT => '3306', //default port is 3306
Database::DB_USER => 'venom',
Database::DB_PASSWORD => 'venomPassword',
Database::DB_DB => 'venomCMS',
Database::DB_EXTRA => '' // need to start with ';'
]);
/**

0
base/lang.base.php Normal file → Executable file
View File

View File

@ -1,9 +1,4 @@
<?php
//register modules -> need to have the Module Class at parent with the init function ;)
$modules = [];
// register controllers that can handle templates ;) need to have a render function for this
$controllers = [
'test' => \Controllers\TestController::class,
];
//register modules -> only apply Module Path! like Meta now the ModuleLoader search for /modules/Meta/module.php!
$modules = [];

18
base/router.base.php Normal file → Executable file
View File

@ -11,19 +11,5 @@ if (!isset($venom)) {
exit(1);
}
$router = new Router('defaultRouter', 1.0, 'api/');
$router->addRoutes([
'/test' => [
'cl' => Route::class,
'roles' => ['ROLE_GUEST'],
'routes' => [
'*' => [
"GET" => 'getAll'
],
'1' => [
"GET" => 'getAll'
]
]
],
]);
$venom->addRouter('defaultRouter', $router);
$router = new Router(Router::DEFAULT_ROUTER, 1.0, 'api/');
$venom->addRouter($router);

View File

@ -5,11 +5,19 @@
"authors": [
{
"name": "Maurice Grönwoldt",
"email": "mauricegroenwoldt@gmail.com"
"email": "mauricegroenwoldt@gmail.com",
"role": "founder"
},
{
"name": "Dominic Seela",
"email": "kontakt@engineertrooper.com",
"role": "friendly developer, supporter"
}
],
"require": {
"ext-pdo": "*"
"ext-pdo": "*",
"ext-http": "*",
"ext-json": "*"
},
"autoload": {
"psr-4": {

0
conf/.gitkeep Normal file → Executable file
View File

View File

@ -7,6 +7,14 @@ create table if not exists seoData
)
comment 'seo url mapping';
create table if not exists metaTagData
(
id int(255) auto_increment not null unique primary key,
content JSON not null,
isActive tinyint(1) default 1 null
)
comment 'Meta Tag File';
create table if not exists language
(
id int(255) auto_increment not null unique primary key,
@ -27,3 +35,26 @@ create table if not exists data
datatype enum ('content', 'form')
)
comment 'DataLoader File';
create table if not exists users
(
id int(255) auto_increment not null unique primary key,
username varchar(255) not null unique,
firstname varchar(255) not null,
lastname varchar(255) not null,
email varchar(255) not null,
password varchar(255) not null,
token varchar(255) not null,
salt varchar(255) not null,
roleId text default '0' not null,
isActive tinyint(1) default 1 null
)
comment 'User File';
create table if not exists roles
(
id int(255) auto_increment not null unique primary key,
name varchar(255) not null unique,
content JSON not null,
isActive tinyint(1) default 1 null
)

0
lang/example.php Normal file → Executable file
View File

0
logs/.gitkeep Normal file → Executable file
View File

0
public/.htaccess Normal file → Executable file
View File

View File

@ -1,7 +0,0 @@
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (/[^.]*|\.)$ [NC]
RewriteRule .* index.php [L]

View File

@ -1,24 +0,0 @@
<?php
use Venom\Core\Config;
use Venom\Core\Setup;
use Venom\Venom;
require_once '../../vendor/autoload.php';
Setup::loadConfig(true);
Setup::loadLanguage();
$config = Config::getInstance();
if ($config->isMaintenance()) {
echo 'Currently not available';
exit;
}
//if devMode is on show all errors!
if ($config->isDevMode()) {
error_reporting(E_ALL);
ini_set('error_reporting', E_ALL);
}
$venom = new Venom();
Setup::loadRouters($venom);
Setup::loadModules($venom);
$venom->run();

0
public/content/.gitkeep Normal file → Executable file
View File

View File

@ -2,10 +2,12 @@
use Venom\Core\Config;
use Venom\Core\Setup;
use Venom\Helper\URLHelper;
use Venom\Venom;
require_once '../vendor/autoload.php';
Setup::loadConfig(false);
session_start();
Setup::loadConfig(URLHelper::getInstance()->isAdminUrl());
Setup::loadLanguage();
$config = Config::getInstance();
@ -21,4 +23,4 @@ if ($config->isDevMode()) {
$venom = new Venom();
Setup::loadRouters($venom);
Setup::loadModules($venom);
$venom->run();
$venom->inject();

View File

@ -0,0 +1 @@
main{display:flex;height:100vh;overflow:hidden}main h1{margin-top:30px;margin-bottom:20px}main h2{margin-top:35px;margin-bottom:25px}main h3{margin-top:20px;margin-bottom:15px}main h4{margin-top:15px;margin-bottom:10px}main.nav-open .menu{transform:translateX(0)}main.nav-open .app{transform:translateX(220px)}main.nav-open .app .nav-toggle span{transition:width .3s;width:0}main.nav-open .app .nav-toggle span:before{transform:translateY(8px) rotate(-135deg)}main.nav-open .app .nav-toggle span:after{transform:translateY(-8px) rotate(135deg)}.app{transform:translateX(0);transition:transform .4s;flex-grow:1;overflow-y:auto;margin:.6rem .8rem;width:100%;max-height:100%;background:rgba(27,27,27,.5);position:relative}.app .nav-toggle{position:absolute;cursor:pointer;left:1rem;height:25px;width:25px}.app .nav-toggle span{transform:translateY(21px)}.app .nav-toggle span,.app .nav-toggle span:after,.app .nav-toggle span:before{border-radius:1px;height:2px;width:25px;background:#fff;position:absolute;content:'';transition:transform .5s,width .4s ease-in}.app .nav-toggle span:before{top:-8px}.app .nav-toggle span:after{bottom:-8px}.menu{width:220px;background-color:#1b1b1b;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23);height:100%;position:fixed;z-index:1;top:0;left:0;overflow-x:hidden;transition:.4s;transform:translateX(-220px);display:flex;flex-direction:column}.menu .logo{text-align:center;font-family:monospace}.menu div[data-link]{padding:.75rem .5rem;position:relative}.menu div[data-link]:after{background-color:#3949ab;content:"";position:absolute;left:0;bottom:0;height:3px;width:100%;transform:scaleX(0);transition:transform .4s;transform-origin:left}.menu div[data-link]:hover:after{transform:scaleX(1)}.menu div[data-link]:last-child{margin-top:auto}.menu div[data-link].active{font-weight:700}.content-area{width:calc(100% - 20px);padding-top:30px;margin:0 auto;display:block}.content-area header{display:block;text-align:center}.content-area header h2{margin:25px 0}.content-area .back-arrow{width:36px;height:36px}.content-area textarea{background:rgba(27,27,27,.5);color:#fff;margin:15px 0 0 0;font-family:sans-serif;font-size:1.1rem;min-width:100%}.content-area .modules div{padding:6px 20px 6px 0}.content-area .add-new,.content-area .overview{width:100%}.content-area .overview div[data-link]{margin-right:10px;padding:10px;background-color:rgba(0,0,0,.3)}.content-area .overview div[data-link]:hover{background-color:rgba(0,0,0,.5)}.content-area .overview .icon{display:inline-block}.content-area .add-new{padding-top:25px}@media only screen and (min-width:768px){.content-area{width:calc(100% - 40px)}.content-area .flexbox{display:flex}.content-area .overview{flex-grow:1;width:60%}.content-area .add-new{padding-top:0;flex-grow:1;width:40%}}@media only screen and (min-width:1024px){.content-area{max-width:860px;padding-top:0;margin:0 0 0 20px}}@media only screen and (min-width:1024px){main,main.nav-open{display:flex}main .app,main.nav-open .app{transform:translateX(0)}main .menu,main.nav-open .menu{position:relative;transform:translateX(0)}main .nav-toggle,main.nav-open .nav-toggle{display:none}}.role-edit .privileges .name{font-size:1.15rem}

View File

@ -0,0 +1 @@
body,html{display:flex;justify-content:center;align-items:center}.hide{display:none!important}#login-background{background-color:rgba(31,31,31,.25);-webkit-filter:blur(10px);filter:blur(10px);position:absolute;top:0;left:0;width:100%;height:100%}login{display:flex;position:relative;max-width:860px;width:90%;height:400px;padding:1rem;border-radius:10px 40px;overflow:hidden;box-shadow:0 10px 20px rgba(0,0,0,.19),0 6px 6px rgba(0,0,0,.23)}#login{z-index:1;display:flex;flex-direction:column;align-items:center;width:100%}#login .logo{width:50%;margin-bottom:20px}#login .error-message{background-color:#c51162;padding:1rem;font-size:.7rem;display:block;width:50%}#login .input-group{width:50%}#login a{text-decoration:none;color:#fff}#login a:hover{color:#3949ab}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg"><symbol viewBox="0 0 24 24" id="vt-add" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></symbol><symbol viewBox="0 0 24 24" id="vt-arrow-back" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></symbol><symbol viewBox="0 0 24 24" id="vt-check" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M19 3H5a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2V5a2 2 0 00-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></symbol><symbol viewBox="0 0 24 24" id="vt-delete" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/><path d="M0 0h24v24H0z" fill="none"/></symbol><symbol viewBox="0 0 24 24" id="vt-edit" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a.996.996 0 000-1.41l-2.34-2.34a.996.996 0 00-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></symbol><symbol viewBox="0 0 24 24" id="vt-visibility" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/></symbol></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -0,0 +1,186 @@
class Component {
constructor(name) {
this.name = name;
this.start();
}
handle(data, ds) {
}
init() {
}
getUrl(ds) {
return '';
}
start() {
if (window.routerIsReady) {
router.addComponent(this.name || VUtils.tempId(), this);
this.init();
} else {
window.addEventListener('routerReady', this.start.bind(this));
}
}
}
class MetaDataComponent extends Component {
constructor() {
super("/metaData");
this.tpl = "metaDataList";
this.tpl2 = "metaDataEdit";
this._url = "/admin/api/metaData";
}
async handle(data, ds) {
let meTpl = ds.id ? this.tpl2 : this.tpl;
await tpl.loadTemplate(meTpl);
return await tpl.renderOn(meTpl, data.content);
}
getUrl(ds) {
let url = this._url;
if (ds.id) {
url += '/' + ds.id;
}
return url;
}
}
class OverviewComponent extends Component {
constructor() {
super("/overview");
this.tpl = "overview";
this._url = "/admin/api/overview";
}
async handle(data, ds) {
await tpl.loadTemplate(this.tpl);
return await tpl.renderOn(this.tpl, data.content);
}
getUrl(ds) {
return this._url;
}
}
class PagesComponent extends Component {
constructor() {
super("/pages");
this.tpl = "pagesList";
this.tpl2 = "pageEdit";
this._url = "/admin/api/pages";
}
async handle(data, ds) {
let meTpl = ds.id ? this.tpl2 : this.tpl;
await tpl.loadTemplate(meTpl);
return await tpl.renderOn(meTpl, data.content);
}
getUrl(ds) {
let url = this._url;
if (ds.id) {
url += '/' + ds.id;
}
return url;
}
}
class RolesComponent extends Component {
constructor() {
super("/roles");
this.tpl = "rolesList";
this.tpl2 = "roleEdit";
this._url = "/admin/api/roles";
}
async handle(data, ds) {
let meTpl = ds.id ? this.tpl2 : this.tpl;
await tpl.loadTemplate(meTpl);
return await tpl.renderOn(meTpl, data.content);
}
getUrl(ds) {
let url = this._url;
if (ds.id) {
url += '/' + ds.id;
}
return url;
}
}
class SeoUrlComponent extends Component {
constructor() {
super("/seoUrl");
this.tpl = "seoUrlList";
this.tpl2 = "seoUrlEdit";
this._url = "/admin/api/seoUrl";
}
async handle(data, ds) {
let meTpl = ds.id ? this.tpl2 : this.tpl;
await tpl.loadTemplate(meTpl);
return await tpl.renderOn(meTpl, data.content);
}
getUrl(ds) {
let url = this._url;
if (ds.id) {
url += '/' + ds.id;
}
return url;
}
}
class UsersComponent extends Component {
constructor() {
super("/users");
this.tpl = "usersList";
this.tpl2 = "userEdit";
this._url = "/admin/api/users";
}
async handle(data, ds) {
let meTpl = ds.id ? this.tpl2 : this.tpl;
await tpl.loadTemplate(meTpl);
return await tpl.renderOn(meTpl, data.content);
}
getUrl(ds) {
let url = this._url;
if (ds.id) {
url += '/' + ds.id;
}
return url;
}
}
class VenomStatusComponent extends Component {
constructor() {
super("/venomStatus");
this.tpl = "venomStatus";
this._url = "/admin/api/venomStatus";
}
async handle(data, ds) {
await tpl.loadTemplate(this.tpl);
return await tpl.renderOn(this.tpl, data.content);
}
getUrl(ds) {
return this._url;
}
}
(() => {
// init all Components ;)
new MetaDataComponent();
new OverviewComponent();
new PagesComponent();
new RolesComponent();
new SeoUrlComponent();
new UsersComponent();
new VenomStatusComponent();
if (routerIsReady) {
document.body.dispatchEvent(new CustomEvent('triggerRouter'));
} else {
document.addEventListener('routerReady', e => {
document.body.dispatchEvent(new CustomEvent('triggerRouter'));
})
}
})();

1
public/theme/admin/js/components.min.js vendored Executable file
View File

@ -0,0 +1 @@
class Component{constructor(t){this.name=t,this.start()}handle(t,e){}init(){}getUrl(t){return""}start(){window.routerIsReady?(router.addComponent(this.name||VUtils.tempId(),this),this.init()):window.addEventListener("routerReady",this.start.bind(this))}}class MetaDataComponent extends Component{constructor(){super("/metaData"),this.tpl="metaDataList",this.tpl2="metaDataEdit",this._url="/admin/api/metaData"}async handle(t,e){let n=e.id?this.tpl2:this.tpl;return await tpl.loadTemplate(n),await tpl.renderOn(n,t.content)}getUrl(t){let e=this._url;return t.id&&(e+="/"+t.id),e}}class OverviewComponent extends Component{constructor(){super("/overview"),this.tpl="overview",this._url="/admin/api/overview"}async handle(t,e){return await tpl.loadTemplate(this.tpl),await tpl.renderOn(this.tpl,t.content)}getUrl(t){return this._url}}class PagesComponent extends Component{constructor(){super("/pages"),this.tpl="pagesList",this.tpl2="pageEdit",this._url="/admin/api/pages"}async handle(t,e){let n=e.id?this.tpl2:this.tpl;return await tpl.loadTemplate(n),await tpl.renderOn(n,t.content)}getUrl(t){let e=this._url;return t.id&&(e+="/"+t.id),e}}class RolesComponent extends Component{constructor(){super("/roles"),this.tpl="rolesList",this.tpl2="roleEdit",this._url="/admin/api/roles"}async handle(t,e){let n=e.id?this.tpl2:this.tpl;return await tpl.loadTemplate(n),await tpl.renderOn(n,t.content)}getUrl(t){let e=this._url;return t.id&&(e+="/"+t.id),e}}class SeoUrlComponent extends Component{constructor(){super("/seoUrl"),this.tpl="seoUrlList",this.tpl2="seoUrlEdit",this._url="/admin/api/seoUrl"}async handle(t,e){let n=e.id?this.tpl2:this.tpl;return await tpl.loadTemplate(n),await tpl.renderOn(n,t.content)}getUrl(t){let e=this._url;return t.id&&(e+="/"+t.id),e}}class UsersComponent extends Component{constructor(){super("/users"),this.tpl="usersList",this.tpl2="userEdit",this._url="/admin/api/users"}async handle(t,e){let n=e.id?this.tpl2:this.tpl;return await tpl.loadTemplate(n),await tpl.renderOn(n,t.content)}getUrl(t){let e=this._url;return t.id&&(e+="/"+t.id),e}}class VenomStatusComponent extends Component{constructor(){super("/venomStatus"),this.tpl="venomStatus",this._url="/admin/api/venomStatus"}async handle(t,e){return await tpl.loadTemplate(this.tpl),await tpl.renderOn(this.tpl,t.content)}getUrl(t){return this._url}}new MetaDataComponent,new OverviewComponent,new PagesComponent,new RolesComponent,new SeoUrlComponent,new UsersComponent,new VenomStatusComponent,routerIsReady?document.body.dispatchEvent(new CustomEvent("triggerRouter")):document.addEventListener("routerReady",t=>{document.body.dispatchEvent(new CustomEvent("triggerRouter"))});

1218
public/theme/admin/js/scripts.js Executable file

File diff suppressed because it is too large Load Diff

1
public/theme/admin/js/scripts.min.js vendored Executable file

File diff suppressed because one or more lines are too long

0
public/theme/default/css/test.css Normal file → Executable file
View File

0
public/theme/default/js/test.js Normal file → Executable file
View File

View File

@ -0,0 +1,51 @@
<?php
namespace Venom\Admin;
use Venom\Entities\RoleEntity;
use Venom\Helper\URLHelper;
use Venom\Security\Security;
use Venom\Views\Asset;
use Venom\Views\RenderController;
use Venom\Views\VenomRenderer;
class AdminController implements RenderController
{
private string $tpl = 'default';
public function register(): bool
{
return true;
}
public function render(VenomRenderer $renderer): bool
{
if (!in_array(URLHelper::getInstance()->getUrl(), ['/admin/', '/admin'])) {
http_response_code(404);
$this->tpl = 'async';
}
$isLogin = Security::get()->hasPermission("admin", RoleEntity::TYPE_READ);
$renderer->addVar('isLoggedIn', $isLogin);
if (!$isLogin) {
Asset::get()->addCSS('login', 'login.css');
} else {
Asset::get()->addCSS('admin', 'admin-panel.css');
}
Asset::get()->addCSS('styles', 'style.css', 1);
Asset::get()->addJS('scripts', 'scripts.min.js', 1);
// Components are the Rendering-Pipeline to know how each Admin-Component needs to be rendered
Asset::get()->addJS('components', 'components.min.js', 5);
return true;
}
public function getTemplate(): string
{
return $this->tpl;
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace Venom\Admin;
use Venom\Admin\Routes\LoginRoute;
use Venom\Admin\Routes\TemplateLoader;
use Venom\Routing\Route;
use Venom\Routing\Router;
use Venom\Venom;
class AdminRouterInit
{
public static function registerAdminRouters(Venom $venom): void
{
$venom->getRouter(Router::ADMIN_ROUTER)->addRoutes(self::getRoutes());
}
public static function getRoutes(): array
{
return [
'/login' => new Route(LoginRoute::class, [
'*' => [
"POST" => 'login'
],
'1' => [
"GET" => 'handle'
]
]),
'/templateLoader' => new Route(TemplateLoader::class, [
'*' => [
"GET" => 'handle'
],
]),
];
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Venom\Admin\Routes;
use Venom\Security\Security;
class LoginRoute
{
public function login(): bool
{
Security::get()->login();
return true;
}
public function handle($fnc): bool
{
if ($fnc === 'logout') {
Security::get()->logout();
echo '{"reload": true}';
die();
}
return true;
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Venom\Admin\Routes;
use Venom\Core\ArgumentHandler;
use Venom\Core\Config;
use Venom\Helper\TemplateUtil;
class TemplateLoader
{
public function handle(): bool
{
if (!Config::getInstance()->isDevMode()) {
header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', time() + (60 * 60 * 60 * 30)));
header('Cache-Control: public');
}
$id = ArgumentHandler::get()->getItem('tpl', '..');
if (strpos($id, '..')) {
return false;
}
echo TemplateUtil::includeTemplate('jsTemplates/' . $id, '.tpl');
die();
}
}

View File

@ -1,12 +1,12 @@
<?php
namespace Venom\Routing;
namespace Venom\Controller;
use Venom\Core\ArgumentHandler;
use Venom\Core\Config;
use Venom\Core\DatabaseHandler;
use Venom\Core\Database\DatabaseHandler;
use Venom\Helper\ErrorHandler;
use Venom\Helper\URLHelper;

View File

@ -8,6 +8,7 @@ class ArgumentHandler
{
public static ?ArgumentHandler $instance = null;
private array $arguments = [];
private array $post = [];
public function __construct()
{
@ -16,6 +17,7 @@ class ArgumentHandler
}
foreach ($_POST as $key => $item) {
$this->arguments[htmlspecialchars($key)] = htmlspecialchars($item);
$this->post[htmlspecialchars($key)] = htmlspecialchars($item);
}
}
@ -41,4 +43,14 @@ class ArgumentHandler
{
return isset($this->arguments[$key]);
}
public function getPostItem(string $key, $default = null)
{
return $this->post[$key] ?? $default;
}
public function hasPostItem(string $key): bool
{
return isset($this->post[$key]);
}
}

3
src/Venom/Core/Config.php Normal file → Executable file
View File

@ -2,7 +2,8 @@
namespace Venom\Core;
use Venom\Models\ConfigObject;
use Venom\Core\Database\DatabaseHandler;
use Venom\Entities\ConfigObject;
class Config
{

View File

@ -0,0 +1,102 @@
<?php
namespace Venom\Core\Database;
// class that hold the Database Connection! and Executes like the DatabaseHandler
use PDO;
use PDOException;
use PDOStatement;
use Venom\Entities\DatabaseObject;
class Database
{
// constants
public const DB_TYPE = 'type';
public const DB_HOST = 'host';
public const DB_PORT = 'port';
public const DB_USER = 'user';
public const DB_PASSWORD = 'pw';
public const DB_DB = 'db';
public const DB_EXTRA = 'extra';
private ?\PDO $db = null;
public function init(array $data): void
{
//init instance with the current data... only working if the db is not init!
if ($this->db != null) {
return;
}
$dsn = '%s:host=%s;dbname=%s;port=%s';
$connectString = sprintf($dsn, $data[self::DB_TYPE], $data[self::DB_HOST], $data[self::DB_DB], $data[self::DB_PORT] . $data[self::DB_EXTRA]);
try {
$this->db = new PDO($connectString, $data[self::DB_USER], $data[self::DB_PASSWORD]);
} catch (PDOException $e) {
trigger_error($e->getMessage());
die($e->getCode());
}
}
public function getOne(string|EasyQuery $query, array $args = []): ?DatabaseObject
{
$sql = $query;
if ($query instanceof EasyQuery) {
$sql = $query->getQuery();
$args = $query->getArgs();
}
$data = $this->getAll($sql, $args);
if (count($data) > 0) {
return $data[0];
}
return null;
}
public function getAll(string|EasyQuery $query, array $args = []): array
{
$sql = $query;
if ($query instanceof EasyQuery) {
$sql = $query->getQuery();
$args = $query->getArgs();
}
$stmt = $this->db->prepare($sql);
$stmt->setFetchMode(PDO::FETCH_CLASS, DatabaseObject::class);
$stmt->execute($args);
return $stmt->fetchAll();
}
public function execute(string|EasyQuery $query, array $args = []): bool
{
$sql = $query;
if ($query instanceof EasyQuery) {
$sql = $query->getQuery();
$args = $query->getArgs();
}
$stmt = $this->db->prepare($sql);
return $stmt->execute($args);
}
public function createStatement($query): bool|PDOStatement
{
$stmt = $this->db->prepare($query);
$stmt->setFetchMode(PDO::FETCH_CLASS, DatabaseObject::class); // set to default fetch-mode :D
return $stmt;
}
public function setClass($stmt, $class)
{
$stmt->setFetchMode(PDO::FETCH_CLASS, $class);
}
public function start()
{
$this->db->beginTransaction();
}
public function commit()
{
$this->db->commit();
}
public function rollBack()
{
$this->db->rollBack();
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace Venom\Core\Database;
class DatabaseHandler
{
private static ?DatabaseHandler $instance = null;
private Database $db;
private array $cache; //EntityManager Cache!
protected function __construct()
{
$this->db = new Database();
}
public static function get(): Database
{
return self::getInstance()->db;
}
public static function getInstance(): DatabaseHandler
{
if (self::$instance === null) {
self::$instance = new DatabaseHandler();
}
return self::$instance;
}
public static function getEntityManager($entityClass): EntityManager
{
$instance = self::getInstance();
// i dont make sure this class exist because the user should do this ;)
if (!isset($instance->cache[$entityClass])) {
$instance->cache[$entityClass] = new EntityManager($entityClass, self::get());
}
return $instance->cache[$entityClass];
}
}

View File

@ -0,0 +1,220 @@
<?php
namespace Venom\Core\Database;
// the QueryBuilder is stupid! dont use it for Very Complex Queries because it's should do Entity Loading Easier :)
class EasyQuery
{
const ORDER_ASC = 0;
const ORDER_DESC = 1;
const WHERE_AND = "AND";
const WHERE_AND_NOT = "AND NOT";
const WHERE_OR = "OR";
const WHERE_OR_NOT = "OR NOT";
const WHERE_NOT = "NOT";
private array $where = [];
private array $args = [];
private string $query = "";
private int $limit = -1;
private int $offset = 0;
private string $whereStmt = "";
private string $havingStmt = "";
private array $order = [];
private array $groupBy = [];
private array $having = [];
public function __construct(private string $tableName, private array $fields = [])
{
}
public static function createSelect(array $fields, string $table): string
{
return "SELECT " . implode(", ", $fields) . " FROM " . $table;
}
public function setWhere(string $statement): static
{
$this->whereStmt = $statement;
return $this;
}
public function setHaving(string $statement): static
{
$this->havingStmt = $statement;
return $this;
}
public function setLimit(int $limit): static
{
$this->limit = $limit;
return $this;
}
public function setOffset(int $offset): static
{
$this->offset = $offset;
return $this;
}
public function addField($field, $as = ""): static
{
if ($as !== "") {
$field .= " AS " . $as;
}
$this->fields[] = $field;
return $this;
}
public function addFields(array $fields): static
{
foreach ($fields as $field) {
$this->fields[] = $field;
}
return $this;
}
public function where($key, $value, $type = "AND"): static
{
$this->where[] = [$key, $type];
$this->args[":" . $key] = $value;
return $this;
}
public function having($key, $value, $type = "AND"): static
{
$this->having[] = [$key, $type];
$this->args[":" . $key] = $value;
return $this;
}
public function orderBy(string $key, int $mode = self::ORDER_ASC): static
{
$this->order[] = $mode === self::ORDER_DESC ? $key . " DESC" : $key;
return $this;
}
public function groupBy(string $key): static
{
$this->groupBy[] = $key;
return $this;
}
public function setArg($key, $value): static
{
$this->args[":" . $key] = $value;
return $this;
}
// returns a Query
public function addArgAndField($key, $value): static
{
$this->args[":" . $key] = $value;
$this->fields[] = $key;
return $this;
}
public function buildSelect(): static
{
// we build an easyQuery Builder that can very easy stuff
$query = self::createSelect($this->fields, $this->tableName);
if (count($this->where) > 0) {
$this->whereStmt = $this->parseStmt($this->where, $this->whereStmt);
}
if (count($this->having) > 0) {
$this->havingStmt = $this->parseStmt($this->having, $this->havingStmt);
}
if ($this->whereStmt !== "") {
$query .= " WHERE " . $this->whereStmt;
}
if (count($this->groupBy)) {
$query .= " GROUP BY " . implode(", ", $this->groupBy);
}
if ($this->havingStmt !== "") {
$query .= " HAVING " . $this->havingStmt;
}
if (count($this->order)) {
$query .= " ORDER BY " . implode(", ", $this->order);
}
if ($this->offset > 0) {
$query .= " OFFSET " . $this->offset;
}
if ($this->limit > 0) {
$query .= " LIMIT " . $this->limit;
}
$this->query = $query;
return $this;
}
public function buildInsertQuery(): static
{
$query = "INSERT INTO " . $this->tableName;
$joinedFields = implode(", ", $this->fields);
$values = implode(", ", array_keys($this->args));
$query .= "(" . $joinedFields . ") VALUES (" . $values . ")";
$this->query = $query;
return $this;
}
public function buildUpdateQuery(): static
{
$query = "UPDATE " . $this->tableName . " SET ";
$setFields = [];
foreach ($this->fields as $field) {
$setFields[] = $field . " = :" . $field;
}
$query .= implode(", ", $setFields);
if (count($this->where) > 0) {
$this->whereStmt = $this->parseStmt($this->where, $this->whereStmt);
}
if ($this->whereStmt !== "") {
$query .= " WHERE " . $this->whereStmt;
}
$this->query = $query;
return $this;
}
public function buildDeleteQuery(): static
{
$query = "DELETE FROM " . $this->tableName;
if (count($this->where) > 0) {
$this->whereStmt = $this->parseStmt($this->where, $this->whereStmt);
}
if ($this->whereStmt !== "") {
$query .= " WHERE " . $this->whereStmt;
}
$this->query = $query;
return $this;
}
public function getQuery(): string
{
return $this->query;
}
public function getArgs(): array
{
return $this->args;
}
public function getFields(): array
{
return $this->fields;
}
private function parseStmt($items, $default = ""): string
{
$query = $default;
foreach ($items as $item) {
if ($query !== "") {
$query .= " " . $item[1] . " ";
}
if ($item[1] === self::WHERE_NOT && $query === "") {
$query .= "NOT ";
}
$query .= $item[0] . " = :" . $item[0];
}
return $query;
}
}

View File

@ -0,0 +1,137 @@
<?php
namespace Venom\Core\Database;
// Entity has a Load and Save function!
// The Entity needs to have a primary key... most of the time this is a id!
use JsonSerializable;
use RuntimeException;
abstract class Entity implements JsonSerializable
{
public static string $tableName = "";
// make sure this exists!
public int $id = -1;
public string $primaryKey = "id";
public array $loadedFields = [];
public array $blackList = ["id"];
// Please override this Property in the Class you implement the Abstract Class! this is needed to run the right SQL calls
public ?array $fields = null;
// Override this if you want special fields :)
public function getLoadedFieldValues(): array
{
$keyValue = [];
foreach ($this->loadedFields as $var) {
$keyValue[$var] = $this->$var;
}
return $keyValue;
}
public function getFieldsToWrite(): array
{
if ($this->fields !== null) {
return $this->fields;
}
$localBlacklist = array_merge(["primaryKey", "tableName", "loadedFields", "blackList", "fields"], $this->blackList);
$allLoaded = in_array("*", $this->loadedFields);
$vars = get_object_vars($this);
foreach ($vars as $key => $var) {
if (in_array($key, $localBlacklist)) {
unset($vars[$key]);
}
}
if (!$allLoaded) {
foreach ($vars as $key => $var) {
if (!in_array($key, $this->loadedFields)) {
unset($vars[$key]);
}
}
}
unset($vars[$this->primaryKey]);
$this->fields = $vars;
return $this->fields;
}
public function save(): bool
{
$this->preSave();
$primaryKey = $this->primaryKey;
$fields = $this->removeEmptyFields($this->getFieldsToWrite());
$query = new EasyQuery(static::$tableName);
foreach ($fields as $key => $field) {
$query->addArgAndField($key, $field);
}
if ($this->$primaryKey === "") {
$query->buildInsertQuery();
} else {
$query->where($primaryKey, $this->$primaryKey)->buildUpdateQuery();
}
return DatabaseHandler::get()->execute($query);
}
public function load($fields = ['*'], ?EasyQuery $query = null): static
{
if ($query === null) {
$primaryKey = $this->primaryKey;
$query = new EasyQuery(static::$tableName, $fields);
$query->where($primaryKey, $this->$primaryKey)->setLimit(1)->buildSelect();
} else {
$query->setLimit(1)->buildSelect();
}
$item = DatabaseHandler::get()->getOne($query);
if ($item === null) {
return $this;
}
$lazy = $item->getData();
$this->id = $item->id;
foreach ($lazy as $key => $item) {
$this->$key = $item;
}
$this->fields = null;
$this->loadedFields = array_merge($this->loadedFields, $query->getFields());
$this->postLoad();
return $this;
}
public function __set($name, $value)
{
// Implement your own if you want to override this behaviour!
throw new RuntimeException("Write to Property: $name that is not Available in the Entity!");
}
public function delete()
{
$key = $this->primaryKey;
$query = new EasyQuery(self::$tableName);
$query->setArg($this->primaryKey, $this->$key)->buildDeleteQuery();
DatabaseHandler::get()->execute($query->getQuery(), $query->getArgs());
}
public function jsonSerialize(): array
{
return $this->getLoadedFieldValues();
}
public function preSave()
{
}
public function postLoad()
{
}
private function removeEmptyFields(array $vars): array
{
foreach ($vars as $name => $item) {
if (empty($item) && $name != $this->primaryKey) {
unset($vars[$name]);
}
}
return $vars;
}
}

View File

@ -0,0 +1,136 @@
<?php
namespace Venom\Core\Database;
use Exception;
class EntityManager
{
/** @var Entity[] */
private array $entities = [];
public function __construct(private string $classType, private Database $db)
{
}
public static function create($callable): EntityManager
{
return DatabaseHandler::getEntityManager($callable);
}
public function createEntity()
{
$ent = new $this->classType;
$this->entities[] = $ent;
return $ent;
}
public function addEntity(Entity $entity)
{
$this->entities[] = $entity;
}
public function removeEntity(Entity $entity)
{
foreach ($this->entities as $key => $item) {
if ($entity === $item) {
unset($this->entities[$key]);
break;
}
}
}
public function findBy($key, $value): ?Entity
{
foreach ($this->entities as $entity) {
if ($entity->$key === $value) {
return $entity;
}
}
return null;
}
public function saveAll(): bool
{
if (count($this->entities) === 0) {
return true;
}
try {
$this->db->start();
foreach ($this->entities as $entity) {
$entity->save();
}
$this->db->commit();
} catch (Exception $ex) {
trigger_error($ex->getMessage());
$this->db->rollBack();
return false;
}
return true;
}
public function deleteEntities(): bool
{
try {
$this->db->start();
foreach ($this->entities as $entity) {
$entity->delete();
}
$this->db->commit();
} catch (Exception $ex) {
trigger_error($ex->getMessage());
$this->db->rollBack();
return false;
}
return true;
}
public function clearAll()
{
$this->entities = [];
}
public function load(string|EasyQuery $query, $args = [], array $fields = ["*"])
{
$sql = $query;
if ($query instanceof EasyQuery) {
$query->buildSelect();
$sql = $query->getQuery();
$args = $query->getArgs();
$fields = $query->getFields();
}
$stmt = $this->db->createStatement($sql);
$this->db->setClass($stmt, $this->classType);
if ($stmt->execute($args)) {
/** @var Entity[] $all */
$all = $stmt->fetchAll();
foreach ($all as $item) {
$item->loadedFields = $fields;
$item->postLoad();
$this->addEntity($item);
}
}
}
public function execute($query): bool
{
return $this->db->execute($query);
}
public function getAll(): array
{
return $this->entities;
}
public function getFirst(): ?Entity
{
return $this->entities[0] ?? null;
}
private function addEntities(array $entities)
{
foreach ($entities as $entity) {
$this->entities[] = $entity;
}
}
}

View File

@ -1,74 +0,0 @@
<?php
namespace Venom\Core;
use PDO;
use PDOException;
use Venom\Models\DatabaseObject;
/**
* Singleton DatabaseHandler... make sure we only have one connection to the database..
* @package Venom\Database
*/
class DatabaseHandler
{
// constants
public const DB_TYPE = 'type';
public const DB_HOST = 'host';
public const DB_PORT = 'port';
public const DB_USER = 'user';
public const DB_PASSWORD = 'pw';
public const DB_DB = 'db';
public const DB_EXTRA = 'extra';
private static ?self $instance = null;
private ?PDO $db = null;
public static function get(): DatabaseHandler
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function init(array $data): void
{
//init instance with the current data... only working if the db is not init!
if ($this->db != null) {
return;
}
$dsn = '%s:host=%s;dbname=%s;port=%s';
$connectString = sprintf($dsn, $data[self::DB_TYPE], $data[self::DB_HOST], $data[self::DB_DB], $data[self::DB_PORT] . $data[self::DB_EXTRA]);
try {
$this->db = new PDO($connectString, $data[self::DB_USER], $data[self::DB_PASSWORD]);
} catch (PDOException $e) {
trigger_error($e->getMessage());
die($e->getCode());
}
}
public function getOne(string $query, array $args): ?DatabaseObject
{
$data = $this->getAll($query, $args);
if (count($data) > 0) {
return $data[0];
}
return null;
}
public function getAll(string $query, array $args): array
{
$stmt = $this->db->prepare($query);
$stmt->setFetchMode(PDO::FETCH_CLASS, DatabaseObject::class);
$stmt->execute($args);
return $stmt->fetchAll();
}
public function execute(string $query, array $args): bool
{
$stmt = $this->db->prepare($query);
return $stmt->execute($args);
}
}

5
src/Venom/Core/Language.php Normal file → Executable file
View File

@ -5,7 +5,8 @@ namespace Venom\Core;
use RuntimeException;
use Venom\Models\DatabaseObject;
use Venom\Core\Database\DatabaseHandler;
use Venom\Entities\DatabaseObject;
class Language
{
@ -20,7 +21,7 @@ class Language
public function initLang()
{
$lang = ArgumentHandler::get()->getItem("lang", $this->defaultLang->shortTag);
$lang = ArgumentHandler::get()->getItem("lang", $this->defaultLang->shortTag ?? 'de');
//check if language exists
$data = DatabaseHandler::get()->getOne("select id from language where shortTag = :shortTag", [
':shortTag' => $lang

15
src/Venom/Core/Module.php Normal file → Executable file
View File

@ -3,10 +3,17 @@
namespace Venom\Core;
interface Module
{
public function register(): bool;
public function init(): void;
const NAME = "name";
const AUTHOR = "author";
const SECURE = "secure";
const ROUTE = "routes";
const ADMIN_ROUTE = "adminRoutes";
const DESC = "description";
const TEMPLATES = "templates";
const ADMIN_TEMPLATES = "adminTemplates";
const CONTROLLER = "controllers";
const TEMPLATE_PATH = "tplPath";
const ACTIVE = "isActive";
}

72
src/Venom/Core/ModuleLoader.php Executable file
View File

@ -0,0 +1,72 @@
<?php
namespace Venom\Core;
use RuntimeException;
use Venom\Helper\TemplateUtil;
use Venom\Routing\Route;
use Venom\Routing\Router;
use Venom\Venom;
class ModuleLoader
{
public static function getModules(): array
{
return [
'Meta',
'User',
'Data',
'Role',
'SEO',
'VenomStatus',
];
}
public static function loadModule(string $name, Venom $venom)
{
// load module search in the Module Path for a module.php file
$dir = __DIR__ . "/../../modules/" . $name . "/module.php";
if (!file_exists($dir)) {
throw new RuntimeException("Module File: \"$dir\" Not found");
}
include_once $dir;
}
public static function initModule(array $module, Venom $venom): bool
{
if (!$module[Module::ACTIVE]) {
return false;
}
// register Router, Templates and more :)
$isAdmin = Config::getInstance()->isAdmin();
if ($isAdmin) {
self::registerRoutes($module,
$venom,
$module[Module::ADMIN_ROUTE],
$venom->getRouter(Router::ADMIN_ROUTER)
);
TemplateUtil::getInstance()->addTemplates($module[Module::ADMIN_TEMPLATES], $module[Module::TEMPLATE_PATH]);
} else {
self::registerRoutes($module,
$venom,
$module[Module::ROUTE],
$venom->getRouter(Router::DEFAULT_ROUTER)
);
TemplateUtil::getInstance()->addTemplates($module[Module::TEMPLATES], $module[Module::TEMPLATE_PATH]);
}
$venom->addControllers($module[Module::CONTROLLER]);
return true;
}
public static function registerRoutes(array $module, Venom $venom, array $routes, Router $router)
{
foreach ($routes as $key => $route) {
/** @var Route $route */
$route->module = $module[Module::NAME];
$route->isSecure = $module[Module::SECURE];
$route->venom = $venom;
$router->addRoute($key, $route);
}
}
}

2
src/Venom/Core/Registry.php Normal file → Executable file
View File

@ -3,7 +3,7 @@
namespace Venom\Core;
use Venom\Routing\SeoController;
use Venom\Controller\SeoController;
/**
* Singleton Class... hold current URL => can

3
src/Venom/Core/Setup.php Normal file → Executable file
View File

@ -39,9 +39,6 @@ class Setup
if (isset($modules)) {
$venom->initModules($modules);
}
if (isset($controllers)) {
$venom->initControllers($controllers);
}
}
public static function loadRouters(Venom $venom): void

View File

@ -1,10 +1,12 @@
<?php
namespace Venom\Models;
namespace Venom\Entities;
class ConfigObject
use Venom\Core\Database\Entity;
class ConfigObject extends Entity
{
private array $data = [];

View File

@ -1,31 +1,25 @@
<?php
namespace Venom\Models;
namespace Venom\Entities;
class DataModel
use Venom\Core\Database\Entity;
class DataEntity extends Entity
{
public const TYPE_CONTENT = 'content';
public const TYPE_FORM = 'form';
public string $id;
public string $raw;
public string $generated;
public string $type;
public int $active = 1;
public function __construct(
string $id,
string $type = self::TYPE_CONTENT,
string $raw = '',
string $generated = ''
public string $id,
public string $type = self::TYPE_CONTENT,
public string $raw = '',
public string $generated = ''
)
{
$this->id = $id;
$this->type = $type;
$this->raw = $raw;
$this->generated = $generated;
}
public function getId(): string

View File

@ -1,15 +1,16 @@
<?php
namespace Venom\Models;
namespace Venom\Entities;
use Venom\Core\Database\Entity;
/**
* Database Object to use queries like this $obj->id, $obj->value
* also the option to print it in csv format ; as delimiter
* @package Venom\Database
*/
class DatabaseObject
class DatabaseObject extends Entity
{
private array $data = [];
@ -26,19 +27,24 @@ class DatabaseObject
$this->data[$name] = $value;
}
public function __isset($name)
public function __isset($name): bool
{
return isset($this->data[$name]);
}
public function toString()
public function toString(): string
{
return implode(';', $this->data);
}
public function getHead()
public function getHead(): string
{
$keys = array_keys($this->data);
return implode(';', $keys);
}
public function getData(): array
{
return $this->data;
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace Venom\Entities;
use Venom\Core\Database\EasyQuery;
use Venom\Core\Database\Entity;
class RoleEntity extends Entity
{
public static string $tableName = "roles";
public string $name = "";
public string $content = "";
public bool $isActive = true;
private array $roles = [];
public const TYPE_WRITE = 1;
public const TYPE_READ = 0;
public const TYPE_NO = -1;
public function hasPermission(string $module, int $type): bool
{
if ($this->id === -1) {
return true;
}
if ($type === self::TYPE_NO) {
return true;
}
if (!isset($this->roles[$module]) && $type) {
return false;
}
$mod = $this->roles[$module];
return $mod["type"] === $type;
}
public function postLoad()
{
if (!empty($this->content)) {
$this->roles = json_decode($this->content);
}
}
public function preSave()
{
$this->content = json_encode($this->roles);
}
public function load($fields = ['*'], ?EasyQuery $query = null): static
{
if ($this->id === -1 || $this->id === 0) {
return $this;
}
return parent::load($fields, $query);
}
}

57
src/Venom/Entities/User.php Executable file
View File

@ -0,0 +1,57 @@
<?php
namespace Venom\Entities;
use Venom\Core\Database\EasyQuery;
use Venom\Core\Database\Entity;
class User extends Entity
{
public const ADMIN_ROLE = '-1';
public const GUEST_ROLE = '0';
public static string $tableName = "users";
public string $username = "GUEST";
public string $firstname = "";
public string $lastname = "";
public string $email = "";
public string $password = "";
public string $token = "";
public string $salt = "";
public int $roleId = 0;
public bool $isActive = true;
private ?RoleEntity $roleEntity = null;
private bool $loaded = false;
public function hasPermission(string $module, $type = RoleEntity::TYPE_WRITE): bool
{
if ($this->roleEntity === null) {
$this->roleEntity = new RoleEntity();
$this->roleEntity->id = $this->roleId;
$this->roleEntity->load();
}
return $this->roleEntity->hasPermission($module, $type);
}
public function postLoad()
{
$this->loaded = true;
}
public function isLoaded(): bool
{
return $this->loaded;
}
public function loadUser()
{
$eq = new EasyQuery(User::$tableName, ["*"]);
$eq->where("username", $this->username)
->where("id", $this->id, EasyQuery::WHERE_OR);
$this->load([], $eq);
return true;
}
}

0
src/Venom/Exceptions/ExceptionHandler.php Normal file → Executable file
View File

View File

@ -0,0 +1,37 @@
<?php
namespace Venom\Helper;
class AdminHelper
{
public static function sendResponse($content, string $component = '', bool $shouldReload = false, $extra = false)
{
$response = [
'content' => $content,
'component' => $component
];
if ($shouldReload) {
$response['reload'] = true;
}
if ($extra) {
$response['extra'] = $extra;
}
echo json_encode($response);
die();
}
public static function sendStatus(bool $isSuccess, string $message = "")
{
if ($message == "") {
$message = $isSuccess ? "Operation Success" : "Operation failed";
}
echo json_encode([
"status" => $isSuccess ? 'success' : 'failed',
"message" => $message
]);
die();
}
}

29
src/Venom/Helper/MetaGenerator.php Normal file → Executable file
View File

@ -4,11 +4,40 @@
namespace Venom\Helper;
use Venom\Core\ArgumentHandler;
use Venom\Core\DatabaseHandler;
/**
* Class MetaGenerator
* @package Venom\Helper
*/
class MetaGenerator
{
private array $container = [];
private string $id;
public function __construct()
{
$this->id = (string)ArgumentHandler::get()->getItem('metaId', '-1');
}
public function loadById(): void
{
if ($this->id === '-1') {
return;
}
$db = DatabaseHandler::get();
$data = $db->getOne('select content from metaTagData where id = :id', [':id' => $this->id]);
if ($data !== null) {
$this->container = json_decode($data->content ?? '', true);
$this->container = array_merge([], $this->container);
}
}
public function render(): void
{
foreach ($this->container as $key => $value) {
echo '<meta name="' . $key . '" content="' . $value . '">';
}
}
}

View File

@ -0,0 +1,75 @@
<?php
namespace Venom\Helper;
use Venom\Core\Config;
class TemplateUtil
{
private static ?TemplateUtil $instance = null;
private string $baseTemplate;
private string $templateDir;
private array $templates = [];
private function __construct()
{
if (Config::getInstance()->isAdmin()) {
$base = 'base';
$theme = 'admin';
} else {
$data = Config::getInstance()->getRenderer();
$theme = $data->theme;
$base = $data->baseFile ?? 'base';
}
$this->baseTemplate = $base . '.php';
$this->templateDir = __DIR__ . '/../../../tpl/' . $theme . '/';
}
public static function getInstance(): TemplateUtil
{
if (self::$instance === null) {
self::$instance = new TemplateUtil();
}
return self::$instance;
}
public function getDir(): string
{
return $this->templateDir;
}
public function getBase(): string
{
return $this->baseTemplate;
}
public function addTemplates($templates, string $basePath)
{
foreach ($templates as $key => $template) {
$this->templates[$key] = $basePath . $template;
}
}
public static function includeTemplate($template, $suffix = '.php'): bool|string
{
$tx = self::getInstance()->getCache($template);
if ($tx === "") {
$dir = self::getInstance()->getDir();
$tx = $dir . $template;
}
$tx .= $suffix;
if (file_exists($tx)) {
ob_start();
include_once $tx;
return ob_get_clean();
}
return '';
}
private function getCache($template)
{
return $this->templates[$template] ?? '';
}
}

5
src/Venom/Helper/URLHelper.php Normal file → Executable file
View File

@ -42,4 +42,9 @@ class URLHelper
{
return $url;
}
public function isAdminUrl(): bool
{
return strpos($this->parsedUrl, '/admin') === 0;
}
}

View File

@ -1,14 +0,0 @@
<?php
namespace Venom\Models;
class User
{
private string $username;
private string $password;
private string $salt;
private string $token;
private array $roles;
}

44
src/Venom/Routing/Route.php Normal file → Executable file
View File

@ -4,7 +4,47 @@
namespace Venom\Routing;
interface Route
{
use RuntimeException;
use Venom\Entities\RoleEntity;
use Venom\Security\Security;
use Venom\Venom;
class Route
{
const GET = "GET";
const POST = "POST";
const PUT = "PUT";
const DELETE = "DELETE";
public string $url;
public array $routes = [];
public int $maxParameters = 0;
public string $module = "unknown";
public bool $isSecure = false;
public Venom $venom;
public function __construct(public string $controller, array $config)
{
$count = count($config);
if ($count === 0) {
throw new RuntimeException("Route: \"$controller\" no valid Routes Found!");
}
$count -= isset($config["*"]) ? 1 : 0;
$this->maxParameters = $count;
$this->routes = $config;
}
public function getDefinitions($method, mixed $subRoute): ?array
{
if ($this->isSecure && !Security::get()->hasPermission($this->module, $method === Route::GET ? RoleEntity::TYPE_READ : RoleEntity::TYPE_WRITE)) {
return null;
}
if (isset($this->routes[$subRoute]) && isset($this->routes[$subRoute][$method])) {
return [
"cl" => $this->controller,
"fnc" => $this->routes[$subRoute][$method]
];
}
return null;
}
}

48
src/Venom/Routing/Router.php Normal file → Executable file
View File

@ -5,9 +5,12 @@ namespace Venom\Routing;
use Exception;
use Venom\Exceptions\ExceptionHandler;
class Router
{
public const DEFAULT_ROUTER = 'defaultRouter';
public const ADMIN_ROUTER = 'adminRouter';
protected string $id = 'defaultRouter';
protected int $version;
protected string $prefix = '';
@ -22,10 +25,10 @@ class Router
public function addRoutes(array $routes): void
{
$this->routes = $routes;
$this->routes = array_merge($this->routes, $routes);
}
public function addRoute(string $path, array $route): void
public function addRoute(string $path, Route $route): void
{
$this->routes[$path] = $route;
}
@ -36,6 +39,7 @@ class Router
public function findRoute($url, $method): ?array
{
$url = $this->removeIfFirst($url, $this->prefix);
$url = $this->removeTrailingSlash($url);
// check if full match... this can easily done if the url isset select the empty!
$method = strtoupper($method);
$route = $this->getRouteByName($url, $method);
@ -51,26 +55,25 @@ class Router
return null;
}
private function removeIfFirst($rawString, $string)
private function removeIfFirst($rawString, $string): bool|string
{
if ($string !== '' && 0 === strpos($rawString, $string)) {
if ($string !== '' && str_starts_with($rawString, $string)) {
return substr($rawString, strlen($string));
}
return $rawString;
}
/* @todo implement Security Check if SecurityModule is used */
private function getRouteByName($url, $method, $subRoute = '*', $params = []): ?array
{
$routeAvailable = isset($this->routes[$url]);
$subRouteFound = isset($this->routes[$url]['routes'][$subRoute]);
$methodFound = isset($this->routes[$url]['routes'][$subRoute][$method]);
if ($routeAvailable && $subRouteFound && $methodFound) {
return [
'cl' => $this->routes[$url]['cl'],
'fnc' => $this->routes[$url]['routes'][$subRoute][$method],
'params' => $params
];
if (isset($this->routes[$url])) {
/** @var Route $route */
$route = $this->routes[$url];
$sub = $route->getDefinitions($method, $subRoute);
if ($sub === null) {
return null;
}
$sub["params"] = array_reverse($params);
return $sub;
}
return null;
}
@ -95,17 +98,32 @@ class Router
public function tryFunctionCall(?array $aRoute): bool
{
if ($aRoute === null || !is_callable(array($aRoute['cl'], $aRoute['fnc']))) {
if ($aRoute === null || empty($aRoute['cl']) || empty($aRoute['fnc']) || !class_exists($aRoute['cl'])) {
return false;
}
$route = new $aRoute['cl']();
if (!is_callable(array($route, $aRoute['fnc']))) {
return false;
}
try {
$fnc = $aRoute['fnc'];
$params = $aRoute['params'] ?? [];
$route->$fnc(...$params);
return true;
} catch (Exception $ex) {
ExceptionHandler::handleException($ex);
return false;
}
}
private function removeTrailingSlash(string $rawString): bool|string
{
$len = strlen($rawString);
return $rawString[$len - 1] === '/' ? substr($rawString, 0, strlen($rawString) - 1) : $rawString;
}
public function getId(): string
{
return $this->id;
}
}

46
src/Venom/Security/BaseLogin.php Normal file → Executable file
View File

@ -4,10 +4,54 @@
namespace Venom\Security;
use Venom\Core\ArgumentHandler;
use Venom\Core\Config;
use Venom\Entities\User;
use Venom\Helper\URLHelper;
/**
* Class that Login stupid via Password, Username
*/
class BaseLogin
class BaseLogin implements Login
{
private User $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function checkCredentials(): bool
{
$handler = ArgumentHandler::get();
return $handler->hasPostItem('USERNAME') && $handler->hasPostItem('PASSWORD');
}
public function redirect(): void
{
$url = ArgumentHandler::get()->getPostItem('REDIRECT_TO', URLHelper::getInstance()->getUrl());
if ($url === 'NO') {
echo json_encode(['message' => 'login'], JSON_THROW_ON_ERROR);
} else {
header('Location: ' . $url);
}
die();
}
public function login(): bool
{
$sec = Config::getInstance()->getSecurity();
$this->user->username = (string)ArgumentHandler::get()->getPostItem('USERNAME');
if (!$this->user->loadUser()) {
return false;
}
$secret = $sec->secret ?? 'venom';
$hashed = hash($sec->algo ?? 'SHA256', ArgumentHandler::get()->getPostItem('PASSWORD') . $secret . $this->user->salt);
if ($this->user->password === $hashed) {
$_SESSION['userID'] = $this->user->id;
return true;
}
return false;
}
}

6
src/Venom/Security/Login.php Normal file → Executable file
View File

@ -4,16 +4,12 @@
namespace Venom\Security;
use Venom\Models\User;
use Venom\Entities\User;
interface Login
{
public function __construct(User $user);
public function checkUsername(): bool;
public function checkPassword(): bool;
public function checkCredentials(): bool;
public function login(): bool;

38
src/Venom/Security/Security.php Normal file → Executable file
View File

@ -3,10 +3,22 @@
namespace Venom\Security;
use RuntimeException;
use Venom\Core\Config;
use Venom\Entities\RoleEntity;
use Venom\Entities\User;
class Security
{
private static ?Security $instance = null;
private ?User $user;
public function __construct()
{
$this->user = new User();
$this->user->id = $_SESSION['userID'] ?? "-1";
$this->user->load();
}
public static function get(): Security
{
@ -16,15 +28,29 @@ class Security
return self::$instance;
}
/* @todo implement logic */
public function hasRole(string $role): bool
public function hasPermission(string $module, $type = RoleEntity::TYPE_WRITE): bool
{
return true;
return $this->user->hasPermission($module, $type);
}
/* @todo implement logic */
public function hasRoles(array $roles): bool
public function login(): void
{
return true;
if ($this->user->isLoaded()) {
throw new RuntimeException('Try to re-login!');
}
$sec = Config::getInstance()->getSecurity();
$login = new $sec->securityClass($this->user);
if ($login instanceof Login) {
if (!$login->checkCredentials() || !$login->login()) {
http_response_code(401);
}
$login->redirect();
}
}
public function logout(): void
{
unset($_SESSION['userID']);
$this->user = new User();
}
}

View File

@ -4,9 +4,12 @@
namespace Venom;
use Venom\Admin\AdminController;
use Venom\Admin\AdminRouterInit;
use Venom\Core\ArgumentHandler;
use Venom\Core\Config;
use Venom\Core\Module;
use Venom\Core\ModuleLoader;
use Venom\Core\Registry;
use Venom\Exceptions\ExceptionHandler;
use Venom\Helper\ErrorHandler;
@ -27,16 +30,26 @@ class Venom
{
ExceptionHandler::setExceptionHandler();
$this->renderer = new VenomRenderer($this);
$this->routers[Router::ADMIN_ROUTER] = new Router(Router::ADMIN_ROUTER, 1.0, '/admin/api');
Asset::get()->setRenderer($this->renderer);
}
public function inject(): void
{
$this->run();
}
public function run(): void
{
$arguments = ArgumentHandler::get();
$arguments->setItem(ErrorHandler::ERROR_KEY, false);
$config = Config::getInstance();
if ($config->isAdmin()) {
$this->initAdmin();
}
// we need to load the current controller and the current start template.
// after this we can start the renderer
if (Config::getInstance()->isRouterEnabled()) {
if ($config->isRouterEnabled() || $config->isAdmin()) {
$status = $this->useRouter();
if ($status['found']) {
if ($status['status']) {
@ -48,18 +61,32 @@ class Venom
$registry = Registry::getInstance();
$registry->getLang()->initLang();
// if site is errored then dont load via SEO
if (!$arguments->getItem(ErrorHandler::ERROR_KEY)) {
if (!$config->isAdmin() && !$arguments->getItem(ErrorHandler::ERROR_KEY)) {
$registry->getSeo()->loadSite();
}
$this->renderer->init($this->findController());
$this->renderer->render();
}
public function initAdmin(): void
{
$this->controllers['adminCtrl'] = AdminController::class;
AdminRouterInit::registerAdminRouters($this);
ArgumentHandler::get()->setItem('cl', 'adminCtrl');
}
private function useRouter(): array
{
$url = URLHelper::getInstance()->getUrl();
$isAdmin = Config::getInstance()->isAdmin();
/** @var Router $router */
foreach ($this->routers as $router) {
foreach ($this->routers as $key => $router) {
if ($isAdmin && $key !== Router::ADMIN_ROUTER) {
continue;
}
if (!$isAdmin && $key === Router::ADMIN_ROUTER) {
continue;
}
$route = $router->findRoute($url, $_SERVER['REQUEST_METHOD']);
$status = $router->tryFunctionCall($route);
if ($route !== null) {
@ -89,21 +116,33 @@ class Venom
public function initModules(array $modules): void
{
foreach ($modules as $key => $moduleClass) {
$module = new $moduleClass;
if ($module instanceof Module && $module->register()) {
$this->modules[$key] = $module;
}
if (Config::getInstance()->isAdmin()) {
$modules = array_merge(ModuleLoader::getModules(), $modules);
}
foreach ($modules as $module) {
ModuleLoader::loadModule($module, $this);
}
}
public function initControllers(array $controllers): void
public function addControllers(array $controllers): void
{
$this->controllers = $controllers;
$this->controllers = array_merge($this->controllers, $controllers);
}
public function addRouter(string $name, Router $router): void
public function addRouter(Router $router): void
{
$this->routers[$name] = $router;
$this->routers[$router->getId()] = $router;
}
public function getRouter(string $router): ?Router
{
return $this->routers[$router];
}
public function registerModule(array $module)
{
if (ModuleLoader::initModule($module, $this)) {
$this->modules[$module[Module::NAME]] = $module;
}
}
}

View File

@ -62,7 +62,7 @@ class Asset
usort($this->jsFiles, function ($a, $b) {
return $a['pos'] <=> $b['pos'];
});
$theme = $this->getPath('/theme/' . Config::getInstance()->getRenderer()->assetDir . '/js/');
$theme = $this->getPath('/js/');
foreach ($this->jsFiles as $key => $file) {
echo '<script src="' . $theme . $file['file'] . '" id="js-' . $key . '"></script>';
}
@ -70,7 +70,8 @@ class Asset
private function getPath($base): string
{
$preDir = $base;
$dir = Config::getInstance()->isAdmin() ? 'admin' : Config::getInstance()->getRenderer()->assetDir;
$preDir = '/theme/' . $dir . $base;
$config = Config::getInstance();
$baseUrl = Config::getInstance()->getBaseUrl();
if ($baseUrl !== '' && $config->getRenderer()->useStaticUrl) {
@ -84,7 +85,7 @@ class Asset
usort($this->cssFiles, function ($a, $b) {
return $a['pos'] <=> $b['pos'];
});
$theme = $this->getPath('/theme/' . Config::getInstance()->getRenderer()->assetDir . '/css/');
$theme = $this->getPath('/css/');
foreach ($this->cssFiles as $key => $file) {
echo '<link rel="stylesheet" href="' . $theme . $file['file'] . '" id="css-' . $key . '">';
}

View File

@ -5,7 +5,7 @@ namespace Venom\Views;
use RuntimeException;
use Venom\Core\DatabaseHandler;
use Venom\Models\DataModel;
use Venom\Entities\DataEntity;
class DataLoader
{
@ -23,7 +23,7 @@ class DataLoader
return self::$instance;
}
public static function loadById(string $id): ?DataModel
public static function loadById(string $id): ?DataEntity
{
if ($id === '') {
throw new RuntimeException('Try to Load empty ID from Database');
@ -33,14 +33,14 @@ class DataLoader
]);
if ($data !== null) {
$model = new DataModel($data->identity, $data->datatype, $data->raw, $data->generated);
$model = new DataEntity($data->identity, $data->datatype, $data->raw, $data->generated);
$model->setActive(true);
return $model;
}
return null;
}
public function updateData(DataModel $model): bool
public function updateData(DataEntity $model): bool
{
if ($model->getId() === '') {
return $this->insertData($model);
@ -57,7 +57,7 @@ class DataLoader
);
}
public function insertData(DataModel $model): bool
public function insertData(DataEntity $model): bool
{
$this->validateModel($model);
@ -73,7 +73,7 @@ class DataLoader
);
}
private function validateModel(DataModel $model): void
private function validateModel(DataEntity $model): void
{
if ($model->getId() === '') {
$model->setId($this->generateID());
@ -87,8 +87,8 @@ class DataLoader
private function generateID(string $id = ''): string
{
if ($id === '') {
$id = bin2hex(random_bytes(16));
$id = bin2hex(random_bytes(32));
}
return $id;
return hash('SHA256', $id);
}
}
}

0
src/Venom/Views/RenderController.php Normal file → Executable file
View File

View File

@ -6,14 +6,17 @@ namespace Venom\Views;
use Venom\Core\ArgumentHandler;
use Venom\Core\Config;
use Venom\Helper\MetaGenerator;
use Venom\Helper\TemplateUtil;
use Venom\Venom;
class VenomRenderer
{
private Venom $venom;
private ?RenderController $controller;
private ?MetaGenerator $metaGenerator;
private string $templateData = '';
private array $vars = [];
private array $vars = [];
private string $baseTemplate = '';
private string $templateDir = '';
@ -50,8 +53,7 @@ class VenomRenderer
public function renderTemplate($template): void
{
// random variable name... to remove it instantly
echo $this->includeTemplate($template, '1408138186');
unset($this->vars['1408138186']);
echo TemplateUtil::includeTemplate($template);
}
/**
@ -62,16 +64,9 @@ class VenomRenderer
*/
public function includeTemplate($template, $varName = '')
{
$template .= '.php';
if (file_exists($this->templateDir . $template)) {
ob_start();
include_once $this->templateDir . $template;
$data = ob_get_clean();
$this->vars[$varName] = $data;
return $data;
}
$this->vars[$varName] = '';
return '';
$data = TemplateUtil::includeTemplate($template);
$this->vars[$varName] = $data;
return $data;
}
public function addVar($name, $value): void
@ -84,7 +79,7 @@ class VenomRenderer
return $this->vars[$name];
}
public function deleteVar($name)
public function deleteVar($name): void
{
unset($this->vars[$name]);
}
@ -92,8 +87,12 @@ class VenomRenderer
public function init(?RenderController $controller): void
{
$this->controller = $controller;
$data = Config::getInstance()->getRenderer();
$this->baseTemplate = $data->baseFile . '.php' ?? 'base.php';
$this->templateDir = __DIR__ . '/../../../tpl/' . $data->theme . '/';
if (!Config::getInstance()->isAdmin()) {
$this->metaGenerator = new MetaGenerator();
$this->metaGenerator->loadById();
}
$util = TemplateUtil::getInstance();
$this->templateDir = $util->getDir();
$this->baseTemplate = $util->getBase();
}
}

0
src/modules/.gitkeep Normal file → Executable file
View File

View File

@ -0,0 +1,13 @@
<?php
namespace Modules\Data\Controller;
class DataController
{
public function get()
{
}
}

34
src/modules/Data/module.php Executable file
View File

@ -0,0 +1,34 @@
<?php
use Modules\Data\Controller\DataController;
use Venom\Core\Module;
use Venom\Routing\Route;
$venom = $venom ?? die();
$venom->registerModule([
Module::ACTIVE => true,
Module::NAME => 'DataModule',
Module::DESC => 'Data Module for Content every',
Module::AUTHOR => 'VstZ dev',
// NEED TO CHECK RIGHTS? :D IF FALSE WRITE IS ALWAYS ALLOWED ALSO READ!
Module::SECURE => true,
Module::ROUTE => [],
Module::ADMIN_ROUTE => [
'/data' => new Route(DataController::class, [
"*" => [
Route::GET => 'get'
]
])
],
Module::TEMPLATE_PATH => __DIR__ . "/tpl/",
Module::TEMPLATES => [
],
Module::ADMIN_TEMPLATES => [
],
Module::CONTROLLER => [
]
]);

View File

@ -0,0 +1,36 @@
<?php
namespace Modules\Meta\Controller;
use Venom\Core\DatabaseHandler;
use Venom\Helper\AdminHelper;
class MetaAPIController
{
public function get()
{
AdminHelper::sendResponse([]);
}
public function getById($id)
{
AdminHelper::sendResponse(SeoUrlController::getById($id));
}
public function update($id)
{
return true;
}
public function delete($id)
{
return true;
}
public function create($id)
{
return true;
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Modules\Meta\Controller;
class MetaController
{
public static function get(): array
{
return [];
}
public static function getById($id): array
{
return [];
}
}

41
src/modules/Meta/module.php Executable file
View File

@ -0,0 +1,41 @@
<?php
use Modules\Meta\Controller\MetaAPIController;
use Venom\Core\Module;
use Venom\Routing\Route;
$venom = $venom ?? die();
$venom->registerModule([
Module::ACTIVE => true,
Module::NAME => 'MetaModule',
Module::DESC => 'Meta Data Module for SEO',
Module::AUTHOR => 'VstZ dev',
// NEED TO CHECK RIGHTS? :D IF FALSE WRITE IS ALWAYS ALLOWED ALSO READ!
Module::SECURE => true,
Module::ROUTE => [],
Module::ADMIN_ROUTE => [
'/metaData' => new Route(MetaAPIController::class, [
"*" => [
Route::GET => 'get'
],
"1" => [
Route::GET => 'getById',
Route::POST => 'update',
Route::PUT => 'insert',
Route::DELETE => 'delete'
]
])
],
Module::TEMPLATE_PATH => __DIR__ . "/tpl/",
Module::TEMPLATES => [
// Include Templates with shorter names! $render->include("meta_roles")
//'meta_roles' => 'PATH_TO_TEMPLATE_FROM_TEMPLATE_PATH'
],
Module::ADMIN_TEMPLATES => [
//
],
Module::CONTROLLER => [
]
]);

View File

@ -0,0 +1,21 @@
<?php
namespace Modules\Role\Controller;
use Venom\Helper\AdminHelper;
class RoleController
{
public function get()
{
AdminHelper::sendResponse([
'roles' => [
['id' => 1, 'name' => 'Admin', 'icon' => 'vt-visibility'],
['id' => 2, 'name' => 'Moderator', 'icon' => 'vt-edit'],
['id' => 3, 'name' => 'Gast', 'icon' => 'vt-edit'],
]
]);
}
}

34
src/modules/Role/module.php Executable file
View File

@ -0,0 +1,34 @@
<?php
use Modules\Role\Controller\RoleController;
use Venom\Core\Module;
use Venom\Routing\Route;
$venom = $venom ?? die();
$venom->registerModule([
Module::ACTIVE => true,
Module::NAME => 'RoleModule',
Module::DESC => 'Role Management',
Module::AUTHOR => 'VstZ dev',
// NEED TO CHECK RIGHTS? :D IF FALSE WRITE IS ALWAYS ALLOWED ALSO READ!
Module::SECURE => true,
Module::ROUTE => [],
Module::ADMIN_ROUTE => [
'/roles' => new Route(RoleController::class, [
"*" => [
Route::GET => 'get'
]
])
],
Module::TEMPLATE_PATH => __DIR__ . "/tpl/",
Module::TEMPLATES => [
],
Module::ADMIN_TEMPLATES => [
],
Module::CONTROLLER => [
]
]);

View File

@ -0,0 +1,18 @@
<?php
namespace Modules\SEO\Controller;
class SeoUrlController
{
public static function get(): array
{
return [];
}
public static function getById($id): array
{
return [];
}
}

40
src/modules/SEO/module.php Executable file
View File

@ -0,0 +1,40 @@
<?php
use Modules\SEO\Controller\SeoUrlController;
use Venom\Core\Module;
use Venom\Routing\Route;
$venom = $venom ?? die();
$venom->registerModule([
Module::ACTIVE => true,
Module::NAME => 'SeoModule',
Module::DESC => 'SEO Management for beautiful URLs',
Module::AUTHOR => 'VstZ dev',
// NEED TO CHECK RIGHTS? :D IF FALSE WRITE IS ALWAYS ALLOWED ALSO READ!
Module::SECURE => true,
Module::ROUTE => [],
Module::ADMIN_ROUTE => [
'/seoUrl' => new Route(SeoUrlController::class, [
"*" => [
Route::GET => 'get'
],
"1" => [
Route::GET => 'getById',
Route::POST => 'update',
Route::PUT => 'insert',
Route::DELETE => 'delete'
]
])
],
Module::TEMPLATE_PATH => __DIR__ . "/tpl/",
Module::TEMPLATES => [
],
Module::ADMIN_TEMPLATES => [
],
Module::CONTROLLER => [
]
]);

View File

@ -0,0 +1,57 @@
<?php
namespace Modules\User\Controller;
use Venom\Core\ArgumentHandler;
use Venom\Core\Database\EasyQuery;
use Venom\Core\Database\EntityManager;
use Venom\Entities\User;
use Venom\Helper\AdminHelper;
class UserAPIController
{
public function get()
{
$entityManager = EntityManager::create(User::class);
$easyQuery = new EasyQuery(User::$tableName, ["id", "username", "firstname", "lastname", "email", "isActive"]);
$entityManager->load($easyQuery);
//['id' => 1, 'name' => 'engineertrooper', 'icon' => 'vt-edit'],
AdminHelper::sendResponse(["users" => $entityManager->getAll()]);
}
public function getById($id)
{
$entityManager = EntityManager::create(User::class);
$easyQuery = new EasyQuery(User::$tableName, ["id", "username", "firstname", "lastname", "email", "isActive"]);
$easyQuery->where("id", $id);
$entityManager->load($easyQuery);
AdminHelper::sendResponse($entityManager->getFirst());
}
public function update($id)
{
$entityManager = EntityManager::create(User::class);
$easyQuery = new EasyQuery(User::$tableName, ["id", "username", "firstname", "lastname", "email", "isActive"]);
$easyQuery->where("id", $id);
$entityManager->load($easyQuery);
/** @var User|null $original */
$original = $entityManager->getFirst();
if ($original == null) {
AdminHelper::sendStatus(false, "User not Found");
}
parse_str(file_get_contents('php://input'), $_PUT);
/* var_dump(array_keys($_PUT));*/
AdminHelper::sendStatus($entityManager->saveAll());
}
public function delete($id)
{
}
public function create($id)
{
// INSERT INTO
AdminHelper::sendStatus(true);
}
}

42
src/modules/User/module.php Executable file
View File

@ -0,0 +1,42 @@
<?php
use Modules\User\Controller\UserAPIController;
use Venom\Core\Module;
use Venom\Routing\Route;
use Venom\Venom;
/** @var Venom $venom */
$venom = $venom ?? die();
$venom->registerModule([
Module::ACTIVE => true,
Module::NAME => 'UserModule',
Module::DESC => 'User Management',
Module::AUTHOR => 'VstZ dev',
// NEED TO CHECK RIGHTS? :D IF FALSE WRITE IS ALWAYS ALLOWED ALSO READ!
Module::SECURE => true,
Module::ROUTE => [],
Module::ADMIN_ROUTE => [
'/users' => new Route(UserAPIController::class, [
"*" => [
Route::GET => 'get'
],
"1" => [
Route::GET => 'getById',
Route::POST => 'update',
Route::PUT => 'update',
Route::DELETE => 'delete'
]
]
)
],
Module::TEMPLATE_PATH => __DIR__ . "/tpl/",
Module::TEMPLATES => [
],
Module::ADMIN_TEMPLATES => [
//
],
Module::CONTROLLER => [
]
]);

View File

@ -0,0 +1,13 @@
<?php
namespace Modules\VenomStatus\Controller;
class VenomStatusController
{
public function get()
{
}
}

View File

@ -0,0 +1,34 @@
<?php
use Modules\VenomStatus\Controller\VenomStatusController;
use Venom\Core\Module;
use Venom\Routing\Route;
$venom = $venom ?? die();
$venom->registerModule([
Module::ACTIVE => true,
Module::NAME => 'VenomStatusModule',
Module::DESC => 'Show Routes and Modules!',
Module::AUTHOR => 'VstZ dev',
// NEED TO CHECK RIGHTS? :D IF FALSE WRITE IS ALWAYS ALLOWED ALSO READ!
Module::SECURE => true,
Module::ROUTE => [],
Module::ADMIN_ROUTE => [
'/venomStatus' => new Route(VenomStatusController::class, [
"*" => [
Route::GET => 'get'
]
])
],
Module::TEMPLATE_PATH => __DIR__ . "/tpl/",
Module::TEMPLATES => [
],
Module::ADMIN_TEMPLATES => [
],
Module::CONTROLLER => [
]
]);

0
tpl/.gitkeep Normal file → Executable file
View File

22
tpl/admin/admin-panel.php Executable file
View File

@ -0,0 +1,22 @@
<main>
<nav class="menu">
<h1 class="logo">Venom</h1>
<div data-link="/metaData">Meta Data</div>
<div data-link="/pages">Pages</div>
<div data-link="/roles">Roles</div>
<div data-link="/seoUrl">SEO-URL</div>
<div data-link="/users">Users</div>
<div data-link="/venomStatus">Venom-Status</div>
<div data-link="/admin/api/login/logout">Ausloggen</div>
</nav>
<div class="app">
<div class="nav-toggle"><span></span></div>
<div class="content-area">
</div>
</div>
<div class="loader hide">
<svg class="spinner" width="65px" height="65px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
<circle class="path" fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle>
</svg>
</div>
</main>

28
tpl/admin/base.php Executable file
View File

@ -0,0 +1,28 @@
<?php
use Venom\Views\Asset;
use Venom\Core\Config;
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Venom Admin Interface</title>
<?php Asset::get()->renderCSS(); ?>
<!--link rel="stylesheet" href="/theme/admin/css/admin-panel.css"-->
</head>
<body <?=Config::getInstance()->isDevMode() ? 'debug' : ''?>>
<?php
if (!$this->getVar('isLoggedIn')) {
$this->renderTemplate('login');
} else {
$this->renderTemplate('admin-panel');
}
Asset::get()->renderJS();
?>
</body>
</html>

View File

@ -0,0 +1,4 @@
<button class="btn btn--${type} ${classes}">
<span class="btn-ripple"></span>
<span class="btn__content">${content}</span>
</button>

View File

@ -0,0 +1,9 @@
<v-input
class="${classes}"
data-label="${label}"
required
name="${name}"
type="${type}"
data-error="${error}"
class="${class}">${default}
</v-input>

View File

@ -0,0 +1,8 @@
<v-select ${required} name="${name}" class="${classes}">
<v-label empty="${label}"></v-label>
<v-options>
{foreach(object as item)}
<v-option value="${item.value}" ${item.selected}>${item.name}</v-option>
{/for}
</v-options>
</v-select>

View File

@ -0,0 +1,3 @@
<svg role="img" class="icon ${class}">
<use href="/theme/admin/icon-sprite.svg#${icon}" xlink:href="/theme/admin/icon-sprite.svg#${icon}"></use>
</svg>

After

Width:  |  Height:  |  Size: 155 B

View File

@ -0,0 +1,5 @@
<v-switch data-id="${id}" class="${classes}">
<input type="checkbox" required name="${name}">
<label></label>
<span>${desc}</span>
</v-switch>

View File

@ -0,0 +1,5 @@
<div class="meta-data">
<header>
<h2>Meta Data</h2>
</header>
</div>

View File

@ -0,0 +1,3 @@
<header>
<h2>Overview</h2>
</header>

View File

@ -0,0 +1,35 @@
<div class="page-edit">
<header>
<h2>Page Edit: Turbinen sind geil</h2>
</header>
<div>
<span data-link="/pages" class="icon-text">
{include(includes/svg;class=back-arrow;icon=vt-arrow-back)}
</span>
</div>
<div>
<h3>Page Information</h3>
{include(includes/input;class=input-group;label=Page Name;name=PageName;error=Page Name is required;default=Turbinen sind geil)}
</div>
<div>
{include(includes/select;name=pageVisibility;label=Current Author;object=$users)}
</div>
<div>
<v-select required name="pageVisibility">
<v-label empty="Page Visibility"></v-label>
<v-options>
<v-option value="visible">Visible</v-option>
<v-option value="privat">Privat</v-option>
</v-options>
</v-select>
</div>
<div>
<v-editor name="pageTextArea" rows="25">!</v-editor>
</div>
<div class="btn-line">
{include(includes/btn;type=valid;content=Save)}
{include(includes/btn;type=primary;content=Reset)}
{include(includes/btn;type=warn;content=Delete Page)}
</div>
</div>

View File

@ -0,0 +1,22 @@
<div class="pages-list">
<header>
<h2>Pages</h2>
</header>
<div class="add-new">
<h3>Add new Page</h3>
{include(includes/input;label=New Page Name;name=newPageName;error=New Page Name is required;type=text)}
{include(includes/btn;type=primary;content=Add)}
</div>
<div class="overview">
<h3>All Pages</h3>
{foreach(pages as page,key)}
<div data-link="/pages" data-id="${page.id}">
<span>
{include(includes/svg;icon=$page.icon)}
</span>
<span>${page.name}</span>
</div>
{/for}
</div>
</div>

View File

@ -0,0 +1,59 @@
<div class="role-edit">
<header>
<h2>Role: ${roles.name}</h2>
</header>
<span data-link="/roles" class="icon-back">
{include(includes/svg;class=back-arrow;icon=vt-arrow-back)}
</span>
<div class="spacer">
{include(includes/switch;id=${switch.id};name=permissionEditMetaData;desc=Active)}
{include(includes/input;class=input-group;label=Name;name=roleName;error=Name is required;default=$roles.name;classes=spacer)}
</div>
<v-table class="privileges">
<h3>Privileges</h3>
<v-table-body>
<v-table-header>
<v-cell class="name">Module</v-cell>
<v-cell class="name">Edit</v-cell>
<v-cell class="name">View</v-cell>
</v-table-header>
<v-table-row>
<v-cell class="description">Meta-Data</v-cell>
<v-cell>{include(includes/switch;id=${switch.id};name=permissionEditMetaData)}</v-cell>
<v-cell>{include(includes/switch;id=${switch.id};name=permissionViewMetaData)}</v-cell>
</v-table-row>
<v-table-row>
<v-cell class="description">Pages</v-cell>
<v-cell>{include(includes/switch;id=${switch.id};name=permissionEditPages)}</v-cell>
<v-cell>{include(includes/switch;id=${switch.id};name=permissionViewPages)}</v-cell>
</v-table-row>
<v-table-row>
<v-cell class="description">Roles</v-cell>
<v-cell>{include(includes/switch;id=${switch.id};name=permissionEditRoles)}</v-cell>
<v-cell>{include(includes/switch;id=${switch.id};name=permissionViewRoles)}</v-cell>
</v-table-row>
<v-table-row>
<v-cell class="description">SEO-URL</v-cell>
<v-cell>{include(includes/switch;id=${switch.id};name=permissionEditSeoUrl)}</v-cell>
<v-cell>{include(includes/switch;id=${switch.id};name=permissionViewSeoUrl)}</v-cell>
</v-table-row>
<v-table-row>
<v-cell class="description">Users</v-cell>
<v-cell>{include(includes/switch;id=${switch.id};name=permissionEditUsers)}</v-cell>
<v-cell>{include(includes/switch;id=${switch.id};name=permissionViewUsers)}</v-cell>
</v-table-row>
<v-table-row>
<v-cell class="description">VENOM-Status</v-cell>
<v-cell>{include(includes/switch;id=${switch.id};name=permissionEditVenomStatus)}</v-cell>
<v-cell>{include(includes/switch;id=${switch.id};name=permissionViewVenomStatus)}</v-cell>
</v-table-row>
</v-table-body>
</v-table>
<div class="btn-line">
<div>
{include(includes/btn;type=valid;content=Save)}
{include(includes/btn;type=primary;content=Reset)}
{include(includes/btn;type=warn;content=Delete Role)}
</div>
</div>
</div>

View File

@ -0,0 +1,23 @@
<div class="roles-list">
<header>
<h2>Roles</h2>
</header>
<div class="flexbox">
<div class="overview">
<h3>Overview</h3>
{foreach(roles as role,key)}
<div data-link="/roles" data-id="${role.id}">
<span>
{include(includes/svg;icon=$role.icon)}
</span>
<span>${role.name}</span>
</div>
{/for}
</div>
<div class="add-new">
<h3>Add new Role</h3>
{include(includes/input;label=New Role Name;name=newRoleName;error=New Role Name is required;type=text)}
{include(includes/btn;type=primary;content=Add)}
</div>
</div>
</div>

View File

@ -0,0 +1,10 @@
<div class="seo-url-list">
<header>
<h2>SEO Urls Edit</h2>
</header>
<div>
<span data-link="/seoUrl" class="icon-text">
{include(includes/svg;class=back-arrow;icon=vt-arrow-back)}
</span>
</div>
</div>

View File

@ -0,0 +1,5 @@
<div class="seo-url-list">
<header>
<h2>SEO Urls</h2>
</header>
</div>

View File

@ -0,0 +1,34 @@
<div class="users-edit">
<header>
<h2>User: ${username}</h2>
</header>
<div>
<span data-link="/users" class="icon-text">
{include(includes/svg;class=back-arrow;icon=vt-arrow-back)}
</span>
</div>
<h3>User-Data</h3>
<form id="user-form" data-id="${id}">
<div class="spacer">
{include(includes/input;class=input-group;label=Username;name=username;error=Username is required;default=$username)}
{include(includes/input;class=input-group;label=Firstname;name=firstname;error=Firstname is required;default=$firstname;classes=spacer)}
{include(includes/input;class=input-group;label=Lastname;name=lastname;error=Lastname is required;default=$lastname;classes=spacer)}
{include(includes/input;class=input-group;label=E-Mail;name=newEMailAddress;error=E-Mail Address is required;default=$email;classes=spacer)}
</div>
<div class="btn-line">
{include(includes/btn;type=valid;content=Save)}
{include(includes/btn;type=warn;content=Delete User)}
</div>
</form>
<h3>Change Password</h3>
<form id="password-form" data-id="${id}">
{include(includes/input;class=input-group;label=Password;name=password;type=password;classes=spacer)}
{include(includes/input;class=input-group;label=Password (Repeat);name=passwordRepeat;type=password;classes=spacer)}
<div class="btn-line">
{include(includes/btn;type=valid;content=Save)}
</div>
</form>
</div>

View File

@ -0,0 +1,23 @@
<div class="users-list">
<header>
<h2>Users</h2>
</header>
</div>
<div class="roles-list">
<div class="flexbox">
<div class="overview">
<h3>Overview</h3>
{foreach(users as user)}
<div data-link="/users" data-id="${user.id}">
<span class="icon-text">
{include(includes/svg;icon=vt-edit)}
</span>
<span>${user.username} (${user.firstname} ${user.lastname})</span>
</div>
{/for}
</div>
<div class="add-new">
{include(includes/btn;type=primary;content=Add User)}
</div>
</div>
</div>

View File

@ -0,0 +1,5 @@
<div class="venom-status">
<header>
<h2>Venom Status</h2>
</header>
</div>

28
tpl/admin/login.php Executable file
View File

@ -0,0 +1,28 @@
<login>
<div id="login-background"></div>
<form id="login" novalidate method="POST" action="/admin/api/login">
<img class="logo" alt="Be Careful" src="/theme/admin/images/logo.svg">
<p class="error-message hide">Login Failed</p>
<input type="hidden" name="REDIRECT_TO" value="NO">
<v-input
class="input-group"
data-label="Username"
required
name="USERNAME"
data-error="Username is required">
</v-input>
<v-input
class="input-group"
data-label="Password"
required
name="PASSWORD"
type="password"
data-error="Password is required">
</v-input>
<button class="btn btn--primary">
<span class="btn-ripple"></span>
<span class="btn__content">Login</span>
</button>
<a href="">Forgotten Password? [not active!]</a>
</form>
</login>

0
tpl/default/base.php Normal file → Executable file
View File