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
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
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
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
3d92f5347a VENOM: FIX PHP8! 2020-11-30 09:01:31 +01:00
5c44d50989 VENOM-10: WIP 2020-11-18 17:50:01 +01:00
8d246aa381 Fix missing TYPE on fucking INPUTS 2020-11-17 22:37:33 +01:00
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
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/routers.inc.php
conf/lang.inc.php conf/lang.inc.php
logs/Exception.log logs/Exception.log
z_dome/
composer.lock
adminer.php

View file

@ -1,18 +1,18 @@
<?php <?php
use Venom\Core\Config; use Venom\Core\Config;
use Venom\Core\DatabaseHandler; use Venom\Core\Database\Database;
$config = Config::getInstance(); $config = Config::getInstance();
$config->setVersion(1.0); $config->setVersion(1.0);
$config->setDatabase([ $config->setDatabase([
DatabaseHandler::DB_TYPE => 'mysql', //please change only if you know what you're doing! this can break a lot. Database::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', Database::DB_HOST => '127.0.0.1',
DatabaseHandler::DB_PORT => '3306', //default port is 3306 Database::DB_PORT => '3306', //default port is 3306
DatabaseHandler::DB_USER => 'venom', Database::DB_USER => 'venom',
DatabaseHandler::DB_PASSWORD => 'venomPassword', Database::DB_PASSWORD => 'venomPassword',
DatabaseHandler::DB_DB => 'venomCMS', Database::DB_DB => 'venomCMS',
DatabaseHandler::DB_EXTRA => '' // need to start with ';' 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 <?php
//register modules -> need to have the Module Class at parent with the init function ;) //register modules -> only apply Module Path! like Meta now the ModuleLoader search for /modules/Meta/module.php!
$modules = []; $modules = [];
// register controllers that can handle templates ;) need to have a render function for this
$controllers = [
'test' => \Controllers\TestController::class,
];

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

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

View file

@ -5,11 +5,19 @@
"authors": [ "authors": [
{ {
"name": "Maurice Grönwoldt", "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": { "require": {
"ext-pdo": "*" "ext-pdo": "*",
"ext-http": "*",
"ext-json": "*"
}, },
"autoload": { "autoload": {
"psr-4": { "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'; 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 create table if not exists language
( (
id int(255) auto_increment not null unique primary key, id int(255) auto_increment not null unique primary key,
@ -27,3 +35,26 @@ create table if not exists data
datatype enum ('content', 'form') datatype enum ('content', 'form')
) )
comment 'DataLoader File'; 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\Config;
use Venom\Core\Setup; use Venom\Core\Setup;
use Venom\Helper\URLHelper;
use Venom\Venom; use Venom\Venom;
require_once '../vendor/autoload.php'; require_once '../vendor/autoload.php';
Setup::loadConfig(false); session_start();
Setup::loadConfig(URLHelper::getInstance()->isAdminUrl());
Setup::loadLanguage(); Setup::loadLanguage();
$config = Config::getInstance(); $config = Config::getInstance();
@ -21,4 +23,4 @@ if ($config->isDevMode()) {
$venom = new Venom(); $venom = new Venom();
Setup::loadRouters($venom); Setup::loadRouters($venom);
Setup::loadModules($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 <?php
namespace Venom\Routing; namespace Venom\Controller;
use Venom\Core\ArgumentHandler; use Venom\Core\ArgumentHandler;
use Venom\Core\Config; use Venom\Core\Config;
use Venom\Core\DatabaseHandler; use Venom\Core\Database\DatabaseHandler;
use Venom\Helper\ErrorHandler; use Venom\Helper\ErrorHandler;
use Venom\Helper\URLHelper; use Venom\Helper\URLHelper;

View file

@ -8,6 +8,7 @@ class ArgumentHandler
{ {
public static ?ArgumentHandler $instance = null; public static ?ArgumentHandler $instance = null;
private array $arguments = []; private array $arguments = [];
private array $post = [];
public function __construct() public function __construct()
{ {
@ -16,6 +17,7 @@ class ArgumentHandler
} }
foreach ($_POST as $key => $item) { foreach ($_POST as $key => $item) {
$this->arguments[htmlspecialchars($key)] = htmlspecialchars($item); $this->arguments[htmlspecialchars($key)] = htmlspecialchars($item);
$this->post[htmlspecialchars($key)] = htmlspecialchars($item);
} }
} }
@ -41,4 +43,14 @@ class ArgumentHandler
{ {
return isset($this->arguments[$key]); 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; namespace Venom\Core;
use Venom\Models\ConfigObject; use Venom\Core\Database\DatabaseHandler;
use Venom\Entities\ConfigObject;
class Config 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 RuntimeException;
use Venom\Models\DatabaseObject; use Venom\Core\Database\DatabaseHandler;
use Venom\Entities\DatabaseObject;
class Language class Language
{ {
@ -20,7 +21,7 @@ class Language
public function initLang() public function initLang()
{ {
$lang = ArgumentHandler::get()->getItem("lang", $this->defaultLang->shortTag); $lang = ArgumentHandler::get()->getItem("lang", $this->defaultLang->shortTag ?? 'de');
//check if language exists //check if language exists
$data = DatabaseHandler::get()->getOne("select id from language where shortTag = :shortTag", [ $data = DatabaseHandler::get()->getOne("select id from language where shortTag = :shortTag", [
':shortTag' => $lang ':shortTag' => $lang

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

@ -3,10 +3,17 @@
namespace Venom\Core; namespace Venom\Core;
interface Module interface Module
{ {
public function register(): bool; const NAME = "name";
const AUTHOR = "author";
public function init(): void; 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; namespace Venom\Core;
use Venom\Routing\SeoController; use Venom\Controller\SeoController;
/** /**
* Singleton Class... hold current URL => can * 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)) { if (isset($modules)) {
$venom->initModules($modules); $venom->initModules($modules);
} }
if (isset($controllers)) {
$venom->initControllers($controllers);
}
} }
public static function loadRouters(Venom $venom): void public static function loadRouters(Venom $venom): void

View file

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

View file

@ -1,31 +1,25 @@
<?php <?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_CONTENT = 'content';
public const TYPE_FORM = 'form'; public const TYPE_FORM = 'form';
public string $id;
public string $raw;
public string $generated;
public string $type;
public int $active = 1; public int $active = 1;
public function __construct( public function __construct(
string $id, public string $id,
string $type = self::TYPE_CONTENT, public string $type = self::TYPE_CONTENT,
string $raw = '', public string $raw = '',
string $generated = '' public string $generated = ''
) )
{ {
$this->id = $id;
$this->type = $type;
$this->raw = $raw;
$this->generated = $generated;
} }
public function getId(): string public function getId(): string

View file

@ -1,15 +1,16 @@
<?php <?php
namespace Venom\Models; namespace Venom\Entities;
use Venom\Core\Database\Entity;
/** /**
* Database Object to use queries like this $obj->id, $obj->value * Database Object to use queries like this $obj->id, $obj->value
* also the option to print it in csv format ; as delimiter * also the option to print it in csv format ; as delimiter
* @package Venom\Database * @package Venom\Database
*/ */
class DatabaseObject class DatabaseObject extends Entity
{ {
private array $data = []; private array $data = [];
@ -26,19 +27,24 @@ class DatabaseObject
$this->data[$name] = $value; $this->data[$name] = $value;
} }
public function __isset($name) public function __isset($name): bool
{ {
return isset($this->data[$name]); return isset($this->data[$name]);
} }
public function toString() public function toString(): string
{ {
return implode(';', $this->data); return implode(';', $this->data);
} }
public function getHead() public function getHead(): string
{ {
$keys = array_keys($this->data); $keys = array_keys($this->data);
return implode(';', $keys); 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; namespace Venom\Helper;
use Venom\Core\ArgumentHandler;
use Venom\Core\DatabaseHandler;
/** /**
* Class MetaGenerator * Class MetaGenerator
* @package Venom\Helper * @package Venom\Helper
*/ */
class MetaGenerator 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; 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; 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 Exception;
use Venom\Exceptions\ExceptionHandler;
class Router class Router
{ {
public const DEFAULT_ROUTER = 'defaultRouter';
public const ADMIN_ROUTER = 'adminRouter';
protected string $id = 'defaultRouter'; protected string $id = 'defaultRouter';
protected int $version; protected int $version;
protected string $prefix = ''; protected string $prefix = '';
@ -22,10 +25,10 @@ class Router
public function addRoutes(array $routes): void 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; $this->routes[$path] = $route;
} }
@ -36,6 +39,7 @@ class Router
public function findRoute($url, $method): ?array public function findRoute($url, $method): ?array
{ {
$url = $this->removeIfFirst($url, $this->prefix); $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! // check if full match... this can easily done if the url isset select the empty!
$method = strtoupper($method); $method = strtoupper($method);
$route = $this->getRouteByName($url, $method); $route = $this->getRouteByName($url, $method);
@ -51,26 +55,25 @@ class Router
return null; 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 substr($rawString, strlen($string));
} }
return $rawString; return $rawString;
} }
/* @todo implement Security Check if SecurityModule is used */
private function getRouteByName($url, $method, $subRoute = '*', $params = []): ?array private function getRouteByName($url, $method, $subRoute = '*', $params = []): ?array
{ {
$routeAvailable = isset($this->routes[$url]); if (isset($this->routes[$url])) {
$subRouteFound = isset($this->routes[$url]['routes'][$subRoute]); /** @var Route $route */
$methodFound = isset($this->routes[$url]['routes'][$subRoute][$method]); $route = $this->routes[$url];
if ($routeAvailable && $subRouteFound && $methodFound) { $sub = $route->getDefinitions($method, $subRoute);
return [ if ($sub === null) {
'cl' => $this->routes[$url]['cl'], return null;
'fnc' => $this->routes[$url]['routes'][$subRoute][$method], }
'params' => $params $sub["params"] = array_reverse($params);
]; return $sub;
} }
return null; return null;
} }
@ -95,17 +98,32 @@ class Router
public function tryFunctionCall(?array $aRoute): bool 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; return false;
} }
$route = new $aRoute['cl'](); $route = new $aRoute['cl']();
if (!is_callable(array($route, $aRoute['fnc']))) {
return false;
}
try { try {
$fnc = $aRoute['fnc']; $fnc = $aRoute['fnc'];
$params = $aRoute['params'] ?? []; $params = $aRoute['params'] ?? [];
$route->$fnc(...$params); $route->$fnc(...$params);
return true; return true;
} catch (Exception $ex) { } catch (Exception $ex) {
ExceptionHandler::handleException($ex);
return false; 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; 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 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; namespace Venom\Security;
use Venom\Models\User; use Venom\Entities\User;
interface Login interface Login
{ {
public function __construct(User $user); public function __construct(User $user);
public function checkUsername(): bool;
public function checkPassword(): bool;
public function checkCredentials(): bool; public function checkCredentials(): bool;
public function login(): bool; public function login(): bool;

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

@ -3,10 +3,22 @@
namespace Venom\Security; namespace Venom\Security;
use RuntimeException;
use Venom\Core\Config;
use Venom\Entities\RoleEntity;
use Venom\Entities\User;
class Security class Security
{ {
private static ?Security $instance = null; 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 public static function get(): Security
{ {
@ -16,15 +28,29 @@ class Security
return self::$instance; return self::$instance;
} }
/* @todo implement logic */ public function hasPermission(string $module, $type = RoleEntity::TYPE_WRITE): bool
public function hasRole(string $role): bool
{ {
return true; return $this->user->hasPermission($module, $type);
} }
/* @todo implement logic */ public function login(): void
public function hasRoles(array $roles): bool
{ {
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; namespace Venom;
use Venom\Admin\AdminController;
use Venom\Admin\AdminRouterInit;
use Venom\Core\ArgumentHandler; use Venom\Core\ArgumentHandler;
use Venom\Core\Config; use Venom\Core\Config;
use Venom\Core\Module; use Venom\Core\Module;
use Venom\Core\ModuleLoader;
use Venom\Core\Registry; use Venom\Core\Registry;
use Venom\Exceptions\ExceptionHandler; use Venom\Exceptions\ExceptionHandler;
use Venom\Helper\ErrorHandler; use Venom\Helper\ErrorHandler;
@ -27,16 +30,26 @@ class Venom
{ {
ExceptionHandler::setExceptionHandler(); ExceptionHandler::setExceptionHandler();
$this->renderer = new VenomRenderer($this); $this->renderer = new VenomRenderer($this);
$this->routers[Router::ADMIN_ROUTER] = new Router(Router::ADMIN_ROUTER, 1.0, '/admin/api');
Asset::get()->setRenderer($this->renderer); Asset::get()->setRenderer($this->renderer);
} }
public function inject(): void
{
$this->run();
}
public function run(): void public function run(): void
{ {
$arguments = ArgumentHandler::get(); $arguments = ArgumentHandler::get();
$arguments->setItem(ErrorHandler::ERROR_KEY, false); $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. // we need to load the current controller and the current start template.
// after this we can start the renderer // after this we can start the renderer
if (Config::getInstance()->isRouterEnabled()) { if ($config->isRouterEnabled() || $config->isAdmin()) {
$status = $this->useRouter(); $status = $this->useRouter();
if ($status['found']) { if ($status['found']) {
if ($status['status']) { if ($status['status']) {
@ -48,18 +61,32 @@ class Venom
$registry = Registry::getInstance(); $registry = Registry::getInstance();
$registry->getLang()->initLang(); $registry->getLang()->initLang();
// if site is errored then dont load via SEO // 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(); $registry->getSeo()->loadSite();
} }
$this->renderer->init($this->findController()); $this->renderer->init($this->findController());
$this->renderer->render(); $this->renderer->render();
} }
public function initAdmin(): void
{
$this->controllers['adminCtrl'] = AdminController::class;
AdminRouterInit::registerAdminRouters($this);
ArgumentHandler::get()->setItem('cl', 'adminCtrl');
}
private function useRouter(): array private function useRouter(): array
{ {
$url = URLHelper::getInstance()->getUrl(); $url = URLHelper::getInstance()->getUrl();
$isAdmin = Config::getInstance()->isAdmin();
/** @var Router $router */ /** @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']); $route = $router->findRoute($url, $_SERVER['REQUEST_METHOD']);
$status = $router->tryFunctionCall($route); $status = $router->tryFunctionCall($route);
if ($route !== null) { if ($route !== null) {
@ -89,21 +116,33 @@ class Venom
public function initModules(array $modules): void public function initModules(array $modules): void
{ {
foreach ($modules as $key => $moduleClass) { if (Config::getInstance()->isAdmin()) {
$module = new $moduleClass; $modules = array_merge(ModuleLoader::getModules(), $modules);
if ($module instanceof Module && $module->register()) {
$this->modules[$key] = $module;
} }
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) { usort($this->jsFiles, function ($a, $b) {
return $a['pos'] <=> $b['pos']; return $a['pos'] <=> $b['pos'];
}); });
$theme = $this->getPath('/theme/' . Config::getInstance()->getRenderer()->assetDir . '/js/'); $theme = $this->getPath('/js/');
foreach ($this->jsFiles as $key => $file) { foreach ($this->jsFiles as $key => $file) {
echo '<script src="' . $theme . $file['file'] . '" id="js-' . $key . '"></script>'; echo '<script src="' . $theme . $file['file'] . '" id="js-' . $key . '"></script>';
} }
@ -70,7 +70,8 @@ class Asset
private function getPath($base): string private function getPath($base): string
{ {
$preDir = $base; $dir = Config::getInstance()->isAdmin() ? 'admin' : Config::getInstance()->getRenderer()->assetDir;
$preDir = '/theme/' . $dir . $base;
$config = Config::getInstance(); $config = Config::getInstance();
$baseUrl = Config::getInstance()->getBaseUrl(); $baseUrl = Config::getInstance()->getBaseUrl();
if ($baseUrl !== '' && $config->getRenderer()->useStaticUrl) { if ($baseUrl !== '' && $config->getRenderer()->useStaticUrl) {
@ -84,7 +85,7 @@ class Asset
usort($this->cssFiles, function ($a, $b) { usort($this->cssFiles, function ($a, $b) {
return $a['pos'] <=> $b['pos']; return $a['pos'] <=> $b['pos'];
}); });
$theme = $this->getPath('/theme/' . Config::getInstance()->getRenderer()->assetDir . '/css/'); $theme = $this->getPath('/css/');
foreach ($this->cssFiles as $key => $file) { foreach ($this->cssFiles as $key => $file) {
echo '<link rel="stylesheet" href="' . $theme . $file['file'] . '" id="css-' . $key . '">'; echo '<link rel="stylesheet" href="' . $theme . $file['file'] . '" id="css-' . $key . '">';
} }

View file

@ -5,7 +5,7 @@ namespace Venom\Views;
use RuntimeException; use RuntimeException;
use Venom\Core\DatabaseHandler; use Venom\Core\DatabaseHandler;
use Venom\Models\DataModel; use Venom\Entities\DataEntity;
class DataLoader class DataLoader
{ {
@ -23,7 +23,7 @@ class DataLoader
return self::$instance; return self::$instance;
} }
public static function loadById(string $id): ?DataModel public static function loadById(string $id): ?DataEntity
{ {
if ($id === '') { if ($id === '') {
throw new RuntimeException('Try to Load empty ID from Database'); throw new RuntimeException('Try to Load empty ID from Database');
@ -33,14 +33,14 @@ class DataLoader
]); ]);
if ($data !== null) { 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); $model->setActive(true);
return $model; return $model;
} }
return null; return null;
} }
public function updateData(DataModel $model): bool public function updateData(DataEntity $model): bool
{ {
if ($model->getId() === '') { if ($model->getId() === '') {
return $this->insertData($model); 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); $this->validateModel($model);
@ -73,7 +73,7 @@ class DataLoader
); );
} }
private function validateModel(DataModel $model): void private function validateModel(DataEntity $model): void
{ {
if ($model->getId() === '') { if ($model->getId() === '') {
$model->setId($this->generateID()); $model->setId($this->generateID());
@ -87,8 +87,8 @@ class DataLoader
private function generateID(string $id = ''): string private function generateID(string $id = ''): string
{ {
if ($id === '') { 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,12 +6,15 @@ namespace Venom\Views;
use Venom\Core\ArgumentHandler; use Venom\Core\ArgumentHandler;
use Venom\Core\Config; use Venom\Core\Config;
use Venom\Helper\MetaGenerator;
use Venom\Helper\TemplateUtil;
use Venom\Venom; use Venom\Venom;
class VenomRenderer class VenomRenderer
{ {
private Venom $venom; private Venom $venom;
private ?RenderController $controller; private ?RenderController $controller;
private ?MetaGenerator $metaGenerator;
private string $templateData = ''; private string $templateData = '';
private array $vars = []; private array $vars = [];
private string $baseTemplate = ''; private string $baseTemplate = '';
@ -50,8 +53,7 @@ class VenomRenderer
public function renderTemplate($template): void public function renderTemplate($template): void
{ {
// random variable name... to remove it instantly // random variable name... to remove it instantly
echo $this->includeTemplate($template, '1408138186'); echo TemplateUtil::includeTemplate($template);
unset($this->vars['1408138186']);
} }
/** /**
@ -62,17 +64,10 @@ class VenomRenderer
*/ */
public function includeTemplate($template, $varName = '') public function includeTemplate($template, $varName = '')
{ {
$template .= '.php'; $data = TemplateUtil::includeTemplate($template);
if (file_exists($this->templateDir . $template)) {
ob_start();
include_once $this->templateDir . $template;
$data = ob_get_clean();
$this->vars[$varName] = $data; $this->vars[$varName] = $data;
return $data; return $data;
} }
$this->vars[$varName] = '';
return '';
}
public function addVar($name, $value): void public function addVar($name, $value): void
{ {
@ -84,7 +79,7 @@ class VenomRenderer
return $this->vars[$name]; return $this->vars[$name];
} }
public function deleteVar($name) public function deleteVar($name): void
{ {
unset($this->vars[$name]); unset($this->vars[$name]);
} }
@ -92,8 +87,12 @@ class VenomRenderer
public function init(?RenderController $controller): void public function init(?RenderController $controller): void
{ {
$this->controller = $controller; $this->controller = $controller;
$data = Config::getInstance()->getRenderer(); if (!Config::getInstance()->isAdmin()) {
$this->baseTemplate = $data->baseFile . '.php' ?? 'base.php'; $this->metaGenerator = new MetaGenerator();
$this->templateDir = __DIR__ . '/../../../tpl/' . $data->theme . '/'; $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