mirror of
https://github.com/typemill/typemill.git
synced 2025-07-30 19:00:32 +02:00
failed try with middleware
This commit is contained in:
@@ -1,33 +1,18 @@
|
||||
const naviBus = new Vue();
|
||||
|
||||
const navcomponent = Vue.component('navigation', {
|
||||
template: '#navigation-template',
|
||||
props: ['homepage', 'name', 'hide', 'newItem', 'parent', 'active', 'filetype', 'status', 'elementtype', 'contains', 'element', 'folder', 'level', 'url', 'root', 'freeze'],
|
||||
props: ['homepage', 'name', 'hide', 'newItem', 'parent', 'active', 'filetype', 'status', 'elementtype', 'contains', 'element', 'folder', 'level', 'url', 'root', 'freeze', 'collapse'],
|
||||
data: function () {
|
||||
return {
|
||||
showForm: false,
|
||||
revert: false,
|
||||
collapse: [],
|
||||
}
|
||||
},
|
||||
mounted: function(){
|
||||
collapse = localStorage.getItem('collapse');
|
||||
if(collapse !== null)
|
||||
{
|
||||
this.collapse = collapse.split(',');
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleCollapse: function(name)
|
||||
callToggle: function(name)
|
||||
{
|
||||
var index = this.collapse.indexOf(name);
|
||||
if (index > -1)
|
||||
{
|
||||
this.collapse.splice(index, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.collapse.push(name);
|
||||
}
|
||||
localStorage.setItem("collapse", this.collapse.toString());
|
||||
naviBus.$emit('toggleNavi', name);
|
||||
},
|
||||
isCollapsed: function(name)
|
||||
{
|
||||
@@ -222,9 +207,46 @@ let navi = new Vue({
|
||||
folderName: '',
|
||||
showForm: false,
|
||||
newItem: '',
|
||||
collapse: [],
|
||||
}
|
||||
},
|
||||
mounted: function(){
|
||||
var collapse = localStorage.getItem('collapse');
|
||||
if(collapse !== null)
|
||||
{
|
||||
var collapseArray = collapse.split(',');
|
||||
var collapseLength = collapseArray.length;
|
||||
var cleanCollapseArray = [];
|
||||
for(var i = 0; i < collapseLength; i++)
|
||||
{
|
||||
if(typeof collapseArray[i] === 'string' && collapseArray[i] != '')
|
||||
{
|
||||
cleanCollapseArray.push(collapseArray[i]);
|
||||
}
|
||||
}
|
||||
this.collapse = collapse.split(',');
|
||||
}
|
||||
naviBus.$on('toggleNavi', this.toggleNavigation);
|
||||
},
|
||||
methods:{
|
||||
clearToggle: function()
|
||||
{
|
||||
this.collapse = [];
|
||||
localStorage.removeItem('collapse');
|
||||
},
|
||||
toggleNavigation: function(name)
|
||||
{
|
||||
var index = this.collapse.indexOf(name);
|
||||
if (index > -1)
|
||||
{
|
||||
this.collapse.splice(index, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.collapse.push(name);
|
||||
}
|
||||
localStorage.setItem("collapse", this.collapse.toString());
|
||||
},
|
||||
checkMove: function(evt){
|
||||
/* this.$refs.draggit[0].checkMove(evt); */
|
||||
if(evt.dragged.classList.contains('folder') && evt.from.parentNode.id != evt.to.parentNode.id)
|
||||
|
@@ -4,6 +4,7 @@
|
||||
<div id="navi" class="content-navi" :value.sync="freeze" v-cloak>
|
||||
<div class="navi-list">
|
||||
<div class="navi-item folder">
|
||||
<div class="foldertoggle" @click="clearToggle"><svg class="icon icon-enlarge2"><use xlink:href="#icon-enlarge2"></use></svg></div>
|
||||
<div class="status" :class="homepage.status"></div>
|
||||
<a href="{{ base_url }}/tm/content/{{ settings.editor }}" :class="homepage.active"><span><span class="iconwrapper"><svg class="icon icon-home"><use xlink:href="#icon-home"></use></svg></span><span class="level-1">{{ __('Homepage') }}</span></a>
|
||||
</div>
|
||||
@@ -15,7 +16,7 @@
|
||||
:move="checkMove"
|
||||
group="file"
|
||||
animation="150"
|
||||
:disabled="freeze">
|
||||
:disabled="freeze">
|
||||
<navigation
|
||||
v-for="item in items"
|
||||
ref="draggit"
|
||||
@@ -34,6 +35,7 @@
|
||||
:filetype="item.fileType"
|
||||
:status="item.status"
|
||||
:folder="item.folderContent"
|
||||
:collapse="collapse"
|
||||
></navigation>
|
||||
</draggable>
|
||||
<ul class="navi-list addBaseItem">
|
||||
@@ -58,7 +60,7 @@
|
||||
{% verbatim %}
|
||||
<template id="navigation-template">
|
||||
<li class="navi-item" :class="elementtype">
|
||||
<div v-if="folder" class="foldertoggle" @click="toggleCollapse(name)"><svg v-if="isCollapsed(name)" class="icon icon-shrink2"><use xlink:href="#icon-shrink2"></use></svg><svg v-else class="icon icon-enlarge2"><use xlink:href="#icon-enlarge2"></use></svg></div>
|
||||
<div v-if="folder" class="foldertoggle" @click="callToggle(name)"><svg v-if="isCollapsed(name)" class="icon icon-shrink2"><use xlink:href="#icon-shrink2"></use></svg><svg v-else class="icon icon-enlarge2"><use xlink:href="#icon-enlarge2"></use></svg></div>
|
||||
<div class="status" :class="status"></div>
|
||||
<a v-bind:href="getUrl(root, url)" :class="checkActive(active,parent)"><span class="iconwrapper"><svg class="icon" :class="getIconClass(elementtype, filetype, hide)"><use :xlink:href="getIcon(elementtype, filetype, hide)"></use></svg></span><span :class="getLevel(level)">{{ name }}</span><span class="movewrapper"><svg class="icon icon-arrows-v"><use xlink:href="#icon-arrows-v"></use></svg></span></a>
|
||||
<draggable v-if="folder" v-show="!isCollapsed(name)" class="navi-list" tag="ul"
|
||||
@@ -88,6 +90,7 @@
|
||||
:elementtype="item.elementType"
|
||||
:contains="item.contains"
|
||||
:folder="item.folderContent"
|
||||
:collapse="collapse"
|
||||
></navigation>
|
||||
</draggable>
|
||||
<ul v-if="folder && contains == 'pages'" class="navi-list">
|
||||
|
499
system/typemill/Controllers/Controller.php
Normal file
499
system/typemill/Controllers/Controller.php
Normal file
@@ -0,0 +1,499 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Controllers;
|
||||
|
||||
use DI\Container;
|
||||
use Slim\Routing\RouteContext;
|
||||
|
||||
# use Psr\Container\ContainerInterface;
|
||||
# use Typemill\Models\Folder;
|
||||
# use Typemill\Models\WriteCache;
|
||||
# use Typemill\Models\WriteYaml;
|
||||
# use Typemill\Events\OnPageReady;
|
||||
# use Typemill\Events\OnPagetreeLoaded;
|
||||
use Typemill\Events\OnTwigLoaded;
|
||||
|
||||
abstract class Controller
|
||||
{
|
||||
# holds the container
|
||||
protected $c;
|
||||
|
||||
# holds the settings
|
||||
protected $settings;
|
||||
|
||||
public function __construct(Container $container)
|
||||
{
|
||||
$this->c = $container;
|
||||
|
||||
$this->routeParser = $container->get('routeParser');
|
||||
|
||||
$this->settings = $container->get('settings');
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
# holds the pimple container
|
||||
protected $c;
|
||||
|
||||
# holds the settings
|
||||
protected $settings;
|
||||
|
||||
# holds the write cache object
|
||||
protected $writeCache;
|
||||
|
||||
# holds the structure of content folder as a serialized array of objects
|
||||
protected $structureDraft = false;
|
||||
|
||||
# holds the structure of content folder as a serialized array of objects
|
||||
protected $structureLive = false;
|
||||
|
||||
# holds the name of the structure-file with drafts for author environment
|
||||
protected $structureDraftName = 'structure-draft.txt';
|
||||
|
||||
# holds the name of the structure-file without drafts for live site
|
||||
protected $structureLiveName = 'structure.txt';
|
||||
|
||||
# holds the frontend navigation without hidden pages
|
||||
protected $navigation = false;
|
||||
|
||||
# holds the list of pages with navigation titles and hidden pages. It extends the structures and navigations
|
||||
protected $extended = false;
|
||||
|
||||
public function __construct(ContainerInterface $c)
|
||||
{
|
||||
$this->c = $c;
|
||||
$this->settings = $this->c->get('settings');
|
||||
|
||||
# used everywhere so instantiate it
|
||||
$this->writeCache = new writeCache();
|
||||
|
||||
$this->c->dispatcher->dispatch('onTwigLoaded');
|
||||
}
|
||||
|
||||
# render page for frontend
|
||||
protected function render($response, $route, $data)
|
||||
{
|
||||
# why commented this out??
|
||||
$data = $this->c->dispatcher->dispatch('onPageReady', new OnPageReady($data))->getData();
|
||||
|
||||
if(isset($_SESSION['old']))
|
||||
{
|
||||
unset($_SESSION['old']);
|
||||
}
|
||||
|
||||
$response = $response->withoutHeader('Server');
|
||||
$response = $response->withAddedHeader('X-Powered-By', 'Typemill');
|
||||
|
||||
if(!isset($this->settings['headersoff']) or !$this->settings['headersoff'])
|
||||
{
|
||||
$response = $response->withAddedHeader('X-Content-Type-Options', 'nosniff');
|
||||
$response = $response->withAddedHeader('X-Frame-Options', 'SAMEORIGIN');
|
||||
$response = $response->withAddedHeader('X-XSS-Protection', '1;mode=block');
|
||||
$response = $response->withAddedHeader('Referrer-Policy', 'no-referrer-when-downgrade');
|
||||
if($this->c->request->getUri()->getScheme() == 'https')
|
||||
{
|
||||
$response = $response->withAddedHeader('Strict-Transport-Security', 'max-age=63072000');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->c->view->render($response, $route, $data);
|
||||
}
|
||||
|
||||
# render 404 for frontend
|
||||
protected function render404($response, $data = NULL)
|
||||
{
|
||||
return $this->c->view->render($response->withStatus(404), '/404.twig', $data);
|
||||
}
|
||||
|
||||
# render page for authors (admin-area)
|
||||
protected function renderIntern($response, $route, $data)
|
||||
{
|
||||
if(isset($_SESSION['old']))
|
||||
{
|
||||
unset($_SESSION['old']);
|
||||
}
|
||||
|
||||
$response = $response->withoutHeader('Server');
|
||||
$response = $response->withAddedHeader('X-Powered-By', 'Typemill');
|
||||
|
||||
if(!isset($this->settings['headersoff']) or !$this->settings['headersoff'])
|
||||
{
|
||||
$response = $response->withAddedHeader('X-Content-Type-Options', 'nosniff');
|
||||
$response = $response->withAddedHeader('X-Frame-Options', 'SAMEORIGIN');
|
||||
$response = $response->withAddedHeader('X-XSS-Protection', '1;mode=block');
|
||||
$response = $response->withAddedHeader('Referrer-Policy', 'no-referrer-when-downgrade');
|
||||
if($this->c->request->getUri()->getScheme() == 'https')
|
||||
{
|
||||
$response = $response->withAddedHeader('Strict-Transport-Security', 'max-age=63072000');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->c->view->render($response, $route, $data);
|
||||
}
|
||||
|
||||
# render 404 for authors
|
||||
protected function renderIntern404($response, $data = NULL)
|
||||
{
|
||||
return $this->c->view->render($response->withStatus(404), '/intern404.twig', $data);
|
||||
}
|
||||
|
||||
# reads the cached structure with published and non-published pages for the author
|
||||
protected function setStructureDraft()
|
||||
{
|
||||
# get the cached structure
|
||||
$this->structureDraft = $this->writeCache->getCache('cache', $this->structureDraftName);
|
||||
|
||||
# if there is no cached structure
|
||||
if(!$this->structureDraft)
|
||||
{
|
||||
return $this->setFreshStructureDraft();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# creates a fresh structure with published and non-published pages for the author
|
||||
protected function setFreshStructureDraft()
|
||||
{
|
||||
# scan the content of the folder
|
||||
$pagetreeDraft = Folder::scanFolder($this->settings['rootPath'] . $this->settings['contentFolder'], $draft = true );
|
||||
|
||||
# if there is content, then get the content details
|
||||
if(count($pagetreeDraft) > 0)
|
||||
{
|
||||
# get the extended structure files with changes like navigation title or hidden pages
|
||||
$yaml = new writeYaml();
|
||||
$extended = $this->getExtended();
|
||||
|
||||
# create an array of object with the whole content of the folder and changes from extended file
|
||||
$this->structureDraft = Folder::getFolderContentDetails($pagetreeDraft, $extended, $this->settings, $this->uri->getBaseUrl(), $this->uri->getBasePath());
|
||||
|
||||
# cache structure draft
|
||||
$this->writeCache->updateCache('cache', $this->structureDraftName, 'lastCache.txt', $this->structureDraft);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
# reads the cached structure of published pages
|
||||
protected function setStructureLive()
|
||||
{
|
||||
# get the cached structure
|
||||
$this->structureLive = $this->writeCache->getCache('cache', $this->structureLiveName);
|
||||
|
||||
# if there is no cached structure
|
||||
if(!$this->structureLive)
|
||||
{
|
||||
return $this->setFreshStructureLive();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# creates a fresh structure with published pages
|
||||
protected function setFreshStructureLive()
|
||||
{
|
||||
# scan the content of the folder
|
||||
$pagetreeLive = Folder::scanFolder($this->settings['rootPath'] . $this->settings['contentFolder'], $draft = false );
|
||||
|
||||
# if there is content, then get the content details
|
||||
if($pagetreeLive && count($pagetreeLive) > 0)
|
||||
{
|
||||
# get the extended structure files with changes like navigation title or hidden pages
|
||||
$yaml = new writeYaml();
|
||||
$extended = $this->getExtended();
|
||||
|
||||
# create an array of object with the whole content of the folder and changes from extended file
|
||||
$this->structureLive = Folder::getFolderContentDetails($pagetreeLive, $extended, $this->settings, $this->uri->getBaseUrl(), $this->uri->getBasePath());
|
||||
|
||||
# cache structure live
|
||||
$this->writeCache->updateCache('cache', $this->structureLiveName, 'lastCache.txt', $this->structureLive);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
# reads the live navigation from cache (live structure without hidden pages)
|
||||
protected function setNavigation()
|
||||
{
|
||||
# get the cached structure
|
||||
$this->navigation = $this->writeCache->getCache('cache', 'navigation.txt');
|
||||
|
||||
# if there is no cached structure
|
||||
if(!$this->navigation)
|
||||
{
|
||||
return $this->setFreshNavigation();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# creates a fresh live navigation (live structure without hidden pages)
|
||||
protected function setFreshNavigation()
|
||||
{
|
||||
|
||||
if(!$this->extended)
|
||||
{
|
||||
$extended = $this->getExtended();
|
||||
}
|
||||
|
||||
if($this->containsHiddenPages($this->extended))
|
||||
{
|
||||
if(!$this->structureLive)
|
||||
{
|
||||
$this->setStructureLive();
|
||||
}
|
||||
|
||||
$structureLive = $this->c->dispatcher->dispatch('onPagetreeLoaded', new OnPagetreeLoaded($this->structureLive))->getData();
|
||||
$this->navigation = $this->createNavigation($structureLive);
|
||||
|
||||
# cache navigation
|
||||
$this->writeCache->updateCache('cache', 'navigation.txt', false, $this->navigation);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# make sure no old navigation file is left
|
||||
$this->writeCache->deleteFileWithPath('cache' . DIRECTORY_SEPARATOR . 'navigation.txt');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
# create navigation from structure
|
||||
protected function createNavigation($structureLive)
|
||||
{
|
||||
foreach ($structureLive as $key => $element)
|
||||
{
|
||||
if($element->hide === true)
|
||||
{
|
||||
unset($structureLive[$key]);
|
||||
}
|
||||
elseif(isset($element->folderContent))
|
||||
{
|
||||
$structureLive[$key]->folderContent = $this->createNavigation($element->folderContent);
|
||||
}
|
||||
}
|
||||
|
||||
return $structureLive;
|
||||
}
|
||||
|
||||
# controllerFrontendWebsite, but not in use, makes no sense to check on each page load
|
||||
public function checkSitemap()
|
||||
{
|
||||
if(!$this->writeCache->getCache('cache', 'sitemap.xml'))
|
||||
{
|
||||
if(!$this->structureLive)
|
||||
{
|
||||
$this->setStructureLive();
|
||||
}
|
||||
|
||||
$this->updateSitemap();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function updateSitemap($ping = false)
|
||||
{
|
||||
$sitemap = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
|
||||
$sitemap .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
|
||||
$sitemap = $this->addUrlSet($sitemap, $this->uri->getBaseUrl());
|
||||
$sitemap .= $this->generateUrlSets($this->structureLive);
|
||||
$sitemap .= '</urlset>';
|
||||
|
||||
$this->writeCache->writeFile('cache', 'sitemap.xml', $sitemap);
|
||||
|
||||
if($ping && isset($this->settings['pingsitemap']) && $this->settings['pingsitemap'])
|
||||
{
|
||||
$sitemapUrl = $this->uri->getBaseUrl() . '/cache/sitemap.xml';
|
||||
|
||||
$pingGoogleUrl = 'http://www.google.com/ping?sitemap=' . urlencode($sitemapUrl);
|
||||
$pingBingUrl = 'http://www.bing.com/ping?sitemap=' . urlencode($sitemapUrl);
|
||||
|
||||
$opts = array(
|
||||
'http'=>array(
|
||||
'method'=>"GET",
|
||||
'ignore_errors' => true,
|
||||
'timeout' => 5
|
||||
)
|
||||
);
|
||||
|
||||
$context = stream_context_create($opts);
|
||||
|
||||
$responseBing = file_get_contents($pingBingUrl, false, $context);
|
||||
$responseGoogle = file_get_contents($pingGoogleUrl, false, $context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function generateUrlSets($structureLive)
|
||||
{
|
||||
$urlset = '';
|
||||
|
||||
foreach($structureLive as $item)
|
||||
{
|
||||
if($item->elementType == 'folder' && isset($item->noindex) && $item->noindex === true)
|
||||
{
|
||||
$urlset .= $this->generateUrlSets($item->folderContent, $urlset);
|
||||
}
|
||||
elseif($item->elementType == 'folder')
|
||||
{
|
||||
$urlset = $this->addUrlSet($urlset, $item->urlAbs);
|
||||
$urlset .= $this->generateUrlSets($item->folderContent, $urlset);
|
||||
}
|
||||
elseif(isset($item->noindex) && $item->noindex === true )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
$urlset = $this->addUrlSet($urlset, $item->urlAbs);
|
||||
}
|
||||
}
|
||||
return $urlset;
|
||||
}
|
||||
|
||||
public function addUrlSet($urlset, $url)
|
||||
{
|
||||
$urlset .= ' <url>' . "\n";
|
||||
$urlset .= ' <loc>' . $url . '</loc>' . "\n";
|
||||
$urlset .= ' </url>' . "\n";
|
||||
return $urlset;
|
||||
}
|
||||
|
||||
protected function getExtended()
|
||||
{
|
||||
$yaml = new writeYaml();
|
||||
|
||||
if(!$this->extended)
|
||||
{
|
||||
$this->extended = $yaml->getYaml('cache', 'structure-extended.yaml');
|
||||
}
|
||||
|
||||
if(!$this->extended)
|
||||
{
|
||||
# scan the content of the folder
|
||||
$pagetreeDraft = Folder::scanFolder($this->settings['rootPath'] . $this->settings['contentFolder'], $draft = true );
|
||||
|
||||
# if there is content, then get the content details
|
||||
if(count($pagetreeDraft) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
# create an array of object with the whole content of the folder and changes from extended file
|
||||
$structureDraft = Folder::getFolderContentDetails($pagetreeDraft, $extended = false, $this->settings, $this->uri->getBaseUrl(), $this->uri->getBasePath());
|
||||
|
||||
$this->extended = $this->createExtended($this->settings['rootPath'] . $this->settings['contentFolder'], $yaml, $structureDraft);
|
||||
|
||||
$yaml->updateYaml('cache', 'structure-extended.yaml', $this->extended);
|
||||
}
|
||||
|
||||
return $this->extended;
|
||||
}
|
||||
|
||||
# creates a file that holds all hide flags and navigation titles
|
||||
# reads all meta-files and creates an array with url => ['hide' => bool, 'navtitle' => 'bla']
|
||||
public function createExtended($contentPath, $yaml, $structureLive, $extended = NULL)
|
||||
{
|
||||
if(!$extended)
|
||||
{
|
||||
$extended = [];
|
||||
}
|
||||
|
||||
foreach ($structureLive as $key => $item)
|
||||
{
|
||||
# $filename = ($item->elementType == 'folder') ? DIRECTORY_SEPARATOR . 'index.yaml' : $item->pathWithoutType . '.yaml';
|
||||
$filename = $item->pathWithoutType . '.yaml';
|
||||
|
||||
if(file_exists($contentPath . $filename))
|
||||
{
|
||||
# read file
|
||||
$meta = $yaml->getYaml('content', $filename);
|
||||
|
||||
$extended[$item->urlRelWoF]['hide'] = isset($meta['meta']['hide']) ? $meta['meta']['hide'] : false;
|
||||
$extended[$item->urlRelWoF]['navtitle'] = isset($meta['meta']['navtitle']) ? $meta['meta']['navtitle'] : '';
|
||||
}
|
||||
|
||||
if ($item->elementType == 'folder')
|
||||
{
|
||||
$extended = $this->createExtended($contentPath, $yaml, $item->folderContent, $extended);
|
||||
}
|
||||
}
|
||||
return $extended;
|
||||
}
|
||||
|
||||
# only backoffice
|
||||
protected function renameExtended($item, $newFolder)
|
||||
{
|
||||
# get the extended structure files with changes like navigation title or hidden pages
|
||||
$yaml = new writeYaml();
|
||||
$extended = $yaml->getYaml('cache', 'structure-extended.yaml');
|
||||
|
||||
if(isset($extended[$item->urlRelWoF]))
|
||||
{
|
||||
$newUrl = $newFolder->urlRelWoF . '/' . $item->slug;
|
||||
|
||||
$entry = $extended[$item->urlRelWoF];
|
||||
|
||||
unset($extended[$item->urlRelWoF]);
|
||||
|
||||
$extended[$newUrl] = $entry;
|
||||
$yaml->updateYaml('cache', 'structure-extended.yaml', $extended);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# only backoffice
|
||||
protected function deleteFromExtended()
|
||||
{
|
||||
# get the extended structure files with changes like navigation title or hidden pages
|
||||
$yaml = new writeYaml();
|
||||
$extended = $yaml->getYaml('cache', 'structure-extended.yaml');
|
||||
|
||||
if($this->item->elementType == "file" && isset($extended[$this->item->urlRelWoF]))
|
||||
{
|
||||
unset($extended[$this->item->urlRelWoF]);
|
||||
$yaml->updateYaml('cache', 'structure-extended.yaml', $extended);
|
||||
}
|
||||
|
||||
if($this->item->elementType == "folder")
|
||||
{
|
||||
$changed = false;
|
||||
|
||||
# delete all entries with that folder url
|
||||
foreach($extended as $url => $entries)
|
||||
{
|
||||
if( strpos($url, $this->item->urlRelWoF) !== false )
|
||||
{
|
||||
$changed = true;
|
||||
unset($extended[$url]);
|
||||
}
|
||||
}
|
||||
|
||||
if($changed)
|
||||
{
|
||||
$yaml->updateYaml('cache', 'structure-extended.yaml', $extended);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# checks if there is a hidden page, returns true on first find
|
||||
protected function containsHiddenPages($extended)
|
||||
{
|
||||
foreach($extended as $element)
|
||||
{
|
||||
if(isset($element['hide']) && $element['hide'] === true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
}
|
54
system/typemill/Controllers/ControllerWeb.php
Normal file
54
system/typemill/Controllers/ControllerWeb.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Controllers;
|
||||
|
||||
use DI\Container;
|
||||
use Slim\Views\Twig;
|
||||
use Typemill\Events\OnTwigLoaded;
|
||||
|
||||
class ControllerWeb extends Controller
|
||||
{
|
||||
public function __construct(Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
|
||||
echo '<br>add twig';
|
||||
|
||||
$settings = $this->settings;
|
||||
|
||||
$csrf = isset($_SESSION) ? $this->c->get('csrf') : false;
|
||||
|
||||
$this->c->set('view', function() use ($settings, $csrf)
|
||||
{
|
||||
$twig = Twig::create(
|
||||
[
|
||||
# path to templates
|
||||
$settings['rootPath'] . $settings['authorFolder'],
|
||||
$settings['rootPath'] . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $settings['theme'],
|
||||
],
|
||||
[
|
||||
# settings
|
||||
'cache' => ( isset($settings['twigcache']) && $settings['twigcache'] ) ? $settings['rootPath'] . '/cache/twig' : false,
|
||||
'debug' => isset($settings['displayErrorDetails'])
|
||||
]
|
||||
);
|
||||
|
||||
# placeholder for flash and errors, will be filled later with middleware
|
||||
$twig->getEnvironment()->addGlobal('errors', NULL);
|
||||
$twig->getEnvironment()->addGlobal('flash', NULL);
|
||||
|
||||
# add extensions
|
||||
$twig->addExtension(new \Twig\Extension\DebugExtension());
|
||||
# $twig->addExtension(new \Nquire\Extensions\TwigUserExtension());
|
||||
if($csrf)
|
||||
{
|
||||
$twig->addExtension(new \Typemill\Extensions\TwigCsrfExtension($csrf));
|
||||
}
|
||||
|
||||
return $twig;
|
||||
});
|
||||
|
||||
$this->c->get('dispatcher')->dispatch(new OnTwigLoaded(false), 'onTwigLoaded');
|
||||
|
||||
}
|
||||
}
|
503
system/typemill/Controllers/ControllerWebFrontend.php
Normal file
503
system/typemill/Controllers/ControllerWebFrontend.php
Normal file
@@ -0,0 +1,503 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Controllers;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Slim\Routing\RouteContext;
|
||||
|
||||
/*
|
||||
use Typemill\Models\Folder;
|
||||
use Typemill\Models\WriteMeta;
|
||||
use Typemill\Extensions\ParsedownExtension;
|
||||
use Typemill\Events\OnPagetreeLoaded;
|
||||
use Typemill\Events\OnBreadcrumbLoaded;
|
||||
use Typemill\Events\OnItemLoaded;
|
||||
use Typemill\Events\OnOriginalLoaded;
|
||||
use Typemill\Events\OnMetaLoaded;
|
||||
use Typemill\Events\OnMarkdownLoaded;
|
||||
use Typemill\Events\OnContentArrayLoaded;
|
||||
use Typemill\Events\OnHtmlLoaded;
|
||||
use Typemill\Events\OnRestrictionsLoaded;
|
||||
*/
|
||||
|
||||
class ControllerWebFrontend extends ControllerWeb
|
||||
{
|
||||
public function index(Request $request, Response $response)
|
||||
{
|
||||
die('hallo');
|
||||
return $this->c->get('view')->render($response, 'home.twig', [
|
||||
'title' => 'Typemill Version 2',
|
||||
'description' => 'Typemill Version 2 wird noch besser als Version 1.'
|
||||
]);
|
||||
|
||||
# Initiate Variables
|
||||
$contentHTML = false;
|
||||
$item = false;
|
||||
$home = false;
|
||||
$breadcrumb = false;
|
||||
$currentpage = false;
|
||||
$this->pathToContent = $this->settings['rootPath'] . $this->settings['contentFolder'];
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
$this->base_url = $this->uri->getBaseUrl();
|
||||
|
||||
# if there is no structure at all, the content folder is probably empty
|
||||
if(!$this->setStructureLive())
|
||||
{
|
||||
return $this->render($response, '/index.twig', array( 'content' => '<h1>No Content</h1><p>Your content folder is empty.</p>' ));
|
||||
}
|
||||
|
||||
# we can create an initial sitemap here, but makes no sense for every pagecall. Sitemap will be created on first author interaction (publish/delete/channge page).
|
||||
# $this->checkSitemap();
|
||||
|
||||
# if the admin activated to refresh the cache automatically each 10 minutes (e.g. use without admin area)
|
||||
if(isset($this->settings['refreshcache']) && $this->settings['refreshcache'] && !$this->writeCache->validate('cache', 'lastCache.txt', 600))
|
||||
{
|
||||
# delete the cache
|
||||
$dir = $this->settings['basePath'] . 'cache';
|
||||
$this->writeCache->deleteCacheFiles($dir);
|
||||
|
||||
# update the internal structure
|
||||
$this->setFreshStructureDraft();
|
||||
|
||||
# update the public structure
|
||||
$this->setFreshStructureLive();
|
||||
|
||||
# update the navigation
|
||||
$this->setFreshNavigation();
|
||||
|
||||
# update the sitemap
|
||||
$this->updateSitemap();
|
||||
}
|
||||
|
||||
# dispatch event and let others manipulate the structure
|
||||
$this->structureLive = $this->c->dispatcher->dispatch('onPagetreeLoaded', new OnPagetreeLoaded($this->structureLive))->getData();
|
||||
|
||||
# check if there is a custom theme css
|
||||
$theme = $this->settings['theme'];
|
||||
$customcss = $this->writeCache->checkFile('cache', $theme . '-custom.css');
|
||||
if($customcss)
|
||||
{
|
||||
$this->c->assets->addCSS($this->base_url . '/cache/' . $theme . '-custom.css');
|
||||
}
|
||||
|
||||
$logo = false;
|
||||
if(isset($this->settings['logo']) && $this->settings['logo'] != '')
|
||||
{
|
||||
# check if logo exists
|
||||
if(file_exists($this->settings['rootPath'] . 'media/live/' . $this->settings['logo']))
|
||||
{
|
||||
$logo = 'media/live/' . $this->settings['logo'];
|
||||
}
|
||||
elseif(file_exists($this->settings['rootPath'] . 'media/files/' . $this->settings['logo']))
|
||||
{
|
||||
$logo = 'media/files/' . $this->settings['logo'];
|
||||
}
|
||||
}
|
||||
|
||||
$favicon = false;
|
||||
if(isset($this->settings['favicon']) && $this->settings['favicon'] != '')
|
||||
{
|
||||
$favicon = true;
|
||||
$this->c->assets->addMeta('tilecolor','<meta name="msapplication-TileColor" content="#F9F8F6" />');
|
||||
$this->c->assets->addMeta('tileimage','<meta name="msapplication-TileImage" content="' . $this->base_url . '/media/files/favicon-144.png" />');
|
||||
$this->c->assets->addMeta('icon16','<link rel="icon" type="image/png" href="' . $this->base_url . '/media/files/favicon-16.png" sizes="16x16" />');
|
||||
$this->c->assets->addMeta('icon32','<link rel="icon" type="image/png" href="' . $this->base_url . '/media/files/favicon-32.png" sizes="32x32" />');
|
||||
$this->c->assets->addMeta('icon72','<link rel="apple-touch-icon" sizes="72x72" href="' . $this->base_url . '/media/files/favicon-72.png" />');
|
||||
$this->c->assets->addMeta('icon114','<link rel="apple-touch-icon" sizes="114x114" href="' . $this->base_url . '/media/files/favicon-114.png" />');
|
||||
$this->c->assets->addMeta('icon144','<link rel="apple-touch-icon" sizes="144x144" href="' . $this->base_url . '/media/files/favicon-144.png" />');
|
||||
$this->c->assets->addMeta('icon180','<link rel="apple-touch-icon" sizes="180x180" href="' . $this->base_url . '/media/files/favicon-180.png" />');
|
||||
}
|
||||
|
||||
# the navigation is a copy of the structure without the hidden pages
|
||||
# hint: if the navigation has been deleted from the cache, then we do not recreate it here to save performace. Instead you have to recreate cache in admin or change a page (publish/unpublish/delete/move)
|
||||
$navigation = $this->writeCache->getCache('cache', 'navigation.txt');
|
||||
if(!$navigation)
|
||||
{
|
||||
# use the structure if there is no cached navigation
|
||||
$navigation = $this->structureLive;
|
||||
}
|
||||
|
||||
# start pagination
|
||||
if(isset($args['params']))
|
||||
{
|
||||
$argSegments = explode("/", $args['params']);
|
||||
|
||||
# check if the last url segment is a number
|
||||
$pageNumber = array_pop($argSegments);
|
||||
if(is_numeric($pageNumber) && $pageNumber < 10000)
|
||||
{
|
||||
# then check if the segment before the page is a "p" that indicates a paginator
|
||||
$pageIndicator = array_pop($argSegments);
|
||||
if($pageIndicator == "p")
|
||||
{
|
||||
# use page number as current page variable
|
||||
$currentpage = $pageNumber;
|
||||
|
||||
# set empty args for startpage
|
||||
$args = [];
|
||||
|
||||
# if there are still params
|
||||
if(!empty($argSegments))
|
||||
{
|
||||
# add them to the args again
|
||||
$args['params'] = implode("/", $argSegments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# if the user is on startpage
|
||||
$home = false;
|
||||
if(empty($args))
|
||||
{
|
||||
$home = true;
|
||||
$item = Folder::getItemForUrl($navigation, $this->uri->getBasePath(), $this->uri->getBaseUrl(), NULL, $home);
|
||||
$urlRel = $this->uri->getBasePath();
|
||||
}
|
||||
else
|
||||
{
|
||||
# get the request url, trim args so physical folders have no trailing slash
|
||||
$urlRel = $this->uri->getBasePath() . '/' . trim($args['params'], "/");
|
||||
|
||||
# find the url in the content-item-tree and return the item-object for the file
|
||||
# important to use the structure here so it is found, even if the item is hidden.
|
||||
$item = Folder::getItemForUrl($this->structureLive, $urlRel, $this->uri->getBasePath());
|
||||
|
||||
# if the item is a folder and if that folder is not hidden
|
||||
if($item && $item->elementType == 'folder' && isset($item->hide) && !$item->hide)
|
||||
{
|
||||
# use the navigation instead of the structure so that hidden elements are erased
|
||||
$item = Folder::getItemForUrl($navigation, $urlRel, $this->uri->getBaseUrl(), NULL, $home);
|
||||
}
|
||||
|
||||
# if there is still no item, return a 404-page
|
||||
if(!$item)
|
||||
{
|
||||
return $this->render404($response, array(
|
||||
'navigation' => $navigation,
|
||||
'settings' => $this->settings,
|
||||
'base_url' => $this->base_url,
|
||||
'title' => false,
|
||||
'content' => false,
|
||||
'item' => false,
|
||||
'breadcrumb' => false,
|
||||
'metatabs' => false,
|
||||
'image' => false,
|
||||
'logo' => $logo,
|
||||
'favicon' => $favicon
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($item->hide))
|
||||
{
|
||||
# if it is a hidden page
|
||||
if($item->hide)
|
||||
{
|
||||
# get breadcrumb for page and set pages active
|
||||
# use structure here because the hidden item is not part of the navigation
|
||||
$breadcrumb = Folder::getBreadcrumb($this->structureLive, $item->keyPathArray);
|
||||
$breadcrumb = $this->c->dispatcher->dispatch('onBreadcrumbLoaded', new OnBreadcrumbLoaded($breadcrumb))->getData();
|
||||
|
||||
# add the paging to the item
|
||||
$item = Folder::getPagingForItem($this->structureLive, $item);
|
||||
}
|
||||
else
|
||||
{
|
||||
# get breadcrumb for page and set pages active
|
||||
# use navigation, because it is used for frontend
|
||||
$breadcrumb = Folder::getBreadcrumb($navigation, $item->keyPathArray);
|
||||
$breadcrumb = $this->c->dispatcher->dispatch('onBreadcrumbLoaded', new OnBreadcrumbLoaded($breadcrumb))->getData();
|
||||
|
||||
# add the paging to the item
|
||||
$item = Folder::getPagingForItem($navigation, $item);
|
||||
}
|
||||
}
|
||||
|
||||
# dispatch the item
|
||||
$item = $this->c->dispatcher->dispatch('onItemLoaded', new OnItemLoaded($item))->getData();
|
||||
|
||||
# set the filepath
|
||||
$filePath = $this->pathToContent . $item->path;
|
||||
|
||||
# check if url is a folder and add index.md
|
||||
if($item->elementType == 'folder')
|
||||
{
|
||||
$filePath = $filePath . DIRECTORY_SEPARATOR . 'index.md';
|
||||
}
|
||||
|
||||
# read the content of the file
|
||||
$contentMD = file_exists($filePath) ? file_get_contents($filePath) : false;
|
||||
|
||||
# dispatch the original content without plugin-manipulations for case anyone wants to use it
|
||||
$this->c->dispatcher->dispatch('onOriginalLoaded', new OnOriginalLoaded($contentMD));
|
||||
|
||||
# initiate object for metadata
|
||||
$writeMeta = new WriteMeta();
|
||||
|
||||
# makes sure that you always have the full meta with title, description and all the rest.
|
||||
$metatabs = $writeMeta->completePageMeta($contentMD, $this->settings, $item);
|
||||
|
||||
# write meta
|
||||
if(isset($metatabs['meta']['noindex']) && $metatabs['meta']['noindex'])
|
||||
{
|
||||
$this->c->assets->addMeta('noindex','<meta name="robots" content="noindex">');
|
||||
}
|
||||
|
||||
$this->c->assets->addMeta('og_site_name','<meta property="og:site_name" content="' . $this->settings['title'] . '">');
|
||||
$this->c->assets->addMeta('og_title','<meta property="og:title" content="' . $metatabs['meta']['title'] . '">');
|
||||
$this->c->assets->addMeta('og_description','<meta property="og:description" content="' . $metatabs['meta']['description'] . '">');
|
||||
$this->c->assets->addMeta('og_type','<meta property="og:type" content="article">');
|
||||
$this->c->assets->addMeta('og_url','<meta property="og:url" content="' . $item->urlAbs . '">');
|
||||
|
||||
# dispatch meta
|
||||
$metatabs = $this->c->dispatcher->dispatch('onMetaLoaded', new OnMetaLoaded($metatabs))->getData();
|
||||
|
||||
# dispatch content
|
||||
$contentMD = $this->c->dispatcher->dispatch('onMarkdownLoaded', new OnMarkdownLoaded($contentMD))->getData();
|
||||
|
||||
$itemUrl = isset($item->urlRel) ? $item->urlRel : false;
|
||||
|
||||
/* initialize parsedown */
|
||||
$parsedown = new ParsedownExtension($this->base_url, $this->settings, $this->c->dispatcher);
|
||||
|
||||
/* set safe mode to escape javascript and html in markdown */
|
||||
$parsedown->setSafeMode(true);
|
||||
|
||||
# check access restriction here
|
||||
$restricted = $this->checkRestrictions($metatabs['meta']);
|
||||
if($restricted)
|
||||
{
|
||||
# convert markdown into array of markdown block-elements
|
||||
$markdownBlocks = $parsedown->markdownToArrayBlocks($contentMD);
|
||||
|
||||
# infos that plugins need to add restriction content
|
||||
$restrictions = [
|
||||
'restricted' => $restricted,
|
||||
'defaultContent' => true,
|
||||
'markdownBlocks' => $markdownBlocks,
|
||||
];
|
||||
|
||||
# dispatch the data
|
||||
$restrictions = $this->c->dispatcher->dispatch('onRestrictionsLoaded', new OnRestrictionsLoaded( $restrictions ))->getData();
|
||||
|
||||
# use the returned markdown
|
||||
$markdownBlocks = $restrictions['markdownBlocks'];
|
||||
|
||||
# if no plugin has disabled the default behavior
|
||||
if($restrictions['defaultContent'])
|
||||
{
|
||||
# cut the restricted content
|
||||
$shortenedPage = $this->cutRestrictedContent($markdownBlocks);
|
||||
|
||||
# check if there is customized content
|
||||
$restrictionnotice = $this->prepareRestrictionNotice();
|
||||
|
||||
# add notice to shortened content
|
||||
$shortenedPage[] = $restrictionnotice;
|
||||
|
||||
# Use the shortened page
|
||||
$markdownBlocks = $shortenedPage;
|
||||
}
|
||||
|
||||
# finally transform the markdown blocks back to pure markdown text
|
||||
$contentMD = $parsedown->arrayBlocksToMarkdown($markdownBlocks);
|
||||
}
|
||||
|
||||
/* parse markdown-file to content-array */
|
||||
$contentArray = $parsedown->text($contentMD);
|
||||
$contentArray = $this->c->dispatcher->dispatch('onContentArrayLoaded', new OnContentArrayLoaded($contentArray))->getData();
|
||||
|
||||
/* parse markdown-content-array to content-string */
|
||||
$contentHTML = $parsedown->markup($contentArray);
|
||||
$contentHTML = $this->c->dispatcher->dispatch('onHtmlLoaded', new OnHtmlLoaded($contentHTML))->getData();
|
||||
|
||||
/* extract the h1 headline*/
|
||||
$contentParts = explode("</h1>", $contentHTML, 2);
|
||||
$title = isset($contentParts[0]) ? strip_tags($contentParts[0]) : $this->settings['title'];
|
||||
|
||||
$contentHTML = isset($contentParts[1]) ? $contentParts[1] : $contentHTML;
|
||||
|
||||
# get the first image from content array */
|
||||
$img_url = isset($metatabs['meta']['heroimage']) ? $metatabs['meta']['heroimage'] : false;
|
||||
$img_alt = isset($metatabs['meta']['heroimagealt']) ? $metatabs['meta']['heroimagealt'] : false;
|
||||
|
||||
# get url and alt-tag for first image, if exists */
|
||||
if(!$img_url OR $img_url == '')
|
||||
{
|
||||
# extract first image from content
|
||||
$firstImageMD = $this->getFirstImage($contentArray);
|
||||
|
||||
if($firstImageMD)
|
||||
{
|
||||
preg_match('#\((.*?)\)#', $firstImageMD, $img_url_result);
|
||||
$img_url = isset($img_url_result[1]) ? $img_url_result[1] : false;
|
||||
|
||||
if($img_url)
|
||||
{
|
||||
preg_match('#\[(.*?)\]#', $firstImageMD, $img_alt_result);
|
||||
$img_alt = isset($img_alt_result[1]) ? $img_alt_result[1] : false;
|
||||
}
|
||||
}
|
||||
elseif($logo)
|
||||
{
|
||||
$img_url = $logo;
|
||||
$pathinfo = pathinfo($this->settings['logo']);
|
||||
$img_alt = $pathinfo['filename'];
|
||||
}
|
||||
}
|
||||
|
||||
$firstImage = false;
|
||||
if($img_url)
|
||||
{
|
||||
$firstImage = array('img_url' => $this->base_url . '/' . $img_url, 'img_alt' => $img_alt);
|
||||
|
||||
$this->c->assets->addMeta('og_image','<meta property="og:image" content="' . $this->base_url . '/' . $img_url . '">');
|
||||
$this->c->assets->addMeta('twitter_image_alt','<meta name="twitter:image:alt" content="' . $img_alt . '">');
|
||||
$this->c->assets->addMeta('twitter_card','<meta name="twitter:card" content="summary_large_image">');
|
||||
}
|
||||
|
||||
$route = empty($args) && isset($this->settings['themes'][$theme]['cover']) ? '/cover.twig' : '/index.twig';
|
||||
|
||||
return $this->render($response, $route, [
|
||||
'home' => $home,
|
||||
'navigation' => $navigation,
|
||||
'title' => $title,
|
||||
'content' => $contentHTML,
|
||||
'item' => $item,
|
||||
'breadcrumb' => $breadcrumb,
|
||||
'settings' => $this->settings,
|
||||
'base_url' => $this->base_url,
|
||||
'metatabs' => $metatabs,
|
||||
'image' => $firstImage,
|
||||
'logo' => $logo,
|
||||
'favicon' => $favicon,
|
||||
'currentpage' => $currentpage
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
protected function getFirstImage(array $contentBlocks)
|
||||
{
|
||||
foreach($contentBlocks as $block)
|
||||
{
|
||||
/* is it a paragraph? */
|
||||
if(isset($block['name']) && $block['name'] == 'p')
|
||||
{
|
||||
if(isset($block['handler']['argument']) && substr($block['handler']['argument'], 0, 2) == '![' )
|
||||
{
|
||||
return $block['handler']['argument'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
# checks if a page has a restriction in meta and if the current user is blocked by that restriction
|
||||
protected function checkRestrictions($meta)
|
||||
{
|
||||
# check if content restrictions are active
|
||||
if(isset($this->settings['pageaccess']) && $this->settings['pageaccess'])
|
||||
{
|
||||
|
||||
# check if page is restricted to certain user
|
||||
if(isset($meta['alloweduser']) && $meta['alloweduser'] && $meta['alloweduser'] !== '' )
|
||||
{
|
||||
$alloweduser = array_map('trim', explode(",", $meta['alloweduser']));
|
||||
if(isset($_SESSION['user']) && in_array($_SESSION['user'], $alloweduser))
|
||||
{
|
||||
# user has access to the page, so there are no restrictions
|
||||
return false;
|
||||
}
|
||||
|
||||
# otherwise return array with type of restriction and allowed username
|
||||
return [ 'alloweduser' => $meta['alloweduser'] ];
|
||||
}
|
||||
|
||||
# check if page is restricted to certain userrole
|
||||
if(isset($meta['allowedrole']) && $meta['allowedrole'] && $meta['allowedrole'] !== '' )
|
||||
{
|
||||
# var_dump($this->c->acl->inheritsRole('editor', 'member'));
|
||||
# die();
|
||||
if(
|
||||
isset($_SESSION['role'])
|
||||
AND (
|
||||
$_SESSION['role'] == 'administrator'
|
||||
OR $_SESSION['role'] == $meta['allowedrole']
|
||||
OR $this->c->acl->inheritsRole($_SESSION['role'], $meta['allowedrole'])
|
||||
)
|
||||
)
|
||||
{
|
||||
# role has access to page, so there are no restrictions
|
||||
return false;
|
||||
}
|
||||
|
||||
return [ 'allowedrole' => $meta['allowedrole'] ];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
protected function cutRestrictedContent($markdown)
|
||||
{
|
||||
#initially add only the title of the page.
|
||||
$restrictedMarkdown = [$markdown[0]];
|
||||
unset($markdown[0]);
|
||||
|
||||
if(isset($this->settings['hrdelimiter']) && $this->settings['hrdelimiter'] !== NULL )
|
||||
{
|
||||
foreach ($markdown as $block)
|
||||
{
|
||||
$firstCharacters = substr($block, 0, 3);
|
||||
if($firstCharacters == '---' OR $firstCharacters == '***')
|
||||
{
|
||||
return $restrictedMarkdown;
|
||||
}
|
||||
$restrictedMarkdown[] = $block;
|
||||
}
|
||||
|
||||
# no delimiter found, so use the title only
|
||||
$restrictedMarkdown = [$restrictedMarkdown[0]];
|
||||
}
|
||||
|
||||
return $restrictedMarkdown;
|
||||
}
|
||||
|
||||
protected function prepareRestrictionNotice()
|
||||
{
|
||||
if( isset($this->settings['restrictionnotice']) && $this->settings['restrictionnotice'] != '' )
|
||||
{
|
||||
$restrictionNotice = $this->settings['restrictionnotice'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$restrictionNotice = 'You are not allowed to access this content.';
|
||||
}
|
||||
|
||||
if( isset($this->settings['wraprestrictionnotice']) && $this->settings['wraprestrictionnotice'] )
|
||||
{
|
||||
# standardize line breaks
|
||||
$text = str_replace(array("\r\n", "\r"), "\n", $restrictionNotice);
|
||||
|
||||
# remove surrounding line breaks
|
||||
$text = trim($text, "\n");
|
||||
|
||||
# split text into lines
|
||||
$lines = explode("\n", $text);
|
||||
|
||||
$restrictionNotice = '';
|
||||
|
||||
foreach($lines as $key => $line)
|
||||
{
|
||||
$restrictionNotice .= "!!!! " . $line . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $restrictionNotice;
|
||||
}
|
||||
}
|
108
system/typemill/Controllers/ControllerWebLogin.php
Normal file
108
system/typemill/Controllers/ControllerWebLogin.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Controllers;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Slim\Routing\RouteContext;
|
||||
|
||||
use Slim\Views\Twig;
|
||||
use Typemill\Models\Validation;
|
||||
use Typemill\Models\User;
|
||||
use Typemill\Models\WriteYaml;
|
||||
use Typemill\Extensions\ParsedownExtension;
|
||||
|
||||
class ControllerWebLogin extends ControllerWeb
|
||||
{
|
||||
# redirect if visit /setup route
|
||||
public function redirect(Request $request, Response $response)
|
||||
{
|
||||
if(isset($_SESSION['login']))
|
||||
{
|
||||
return $response->withRedirect($this->c->router->pathFor('content.raw'));
|
||||
}
|
||||
else
|
||||
{
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* show login form
|
||||
*
|
||||
* @param obj $request the slim request object.
|
||||
* @param obj $response the slim response object.
|
||||
* @param array $args with arguments past to the slim router
|
||||
* @return obj $response and string route.
|
||||
*/
|
||||
|
||||
public function show(Request $request, Response $response, $args)
|
||||
{
|
||||
return $this->c->get('view')->render($response, 'login.twig', [
|
||||
#'captcha' => $this->checkIfAddCaptcha(),
|
||||
#'url' => $this->urlCollection,
|
||||
]);
|
||||
|
||||
# $settings = $this->c->get('settings');
|
||||
|
||||
# return $this->render($response, '/auth/login.twig', ['settings' => $settings]);
|
||||
}
|
||||
|
||||
/**
|
||||
* signin an existing user
|
||||
*
|
||||
* @param obj $request the slim request object with form data in the post params.
|
||||
* @param obj $response the slim response object.
|
||||
* @return obj $response with redirect to route.
|
||||
*/
|
||||
|
||||
public function login(Request $request, Response $response)
|
||||
{
|
||||
if( ( null !== $request->getattribute('csrf_result') ) OR ( $request->getattribute('csrf_result') === false ) )
|
||||
{
|
||||
$this->c->flash->addMessage('error', 'The form has a timeout, please try again.');
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
}
|
||||
|
||||
/* authentication */
|
||||
$params = $request->getParams();
|
||||
$validation = new Validation();
|
||||
$settings = $this->c->get('settings');
|
||||
|
||||
if($validation->signin($params))
|
||||
{
|
||||
$user = new User();
|
||||
$userdata = $user->getUser($params['username']);
|
||||
|
||||
if($userdata && password_verify($params['password'], $userdata['password']))
|
||||
{
|
||||
# check if user has confirmed the account
|
||||
if(isset($userdata['optintoken']) && $userdata['optintoken'])
|
||||
{
|
||||
$this->c->flash->addMessage('error', 'Your registration is not confirmed yet. Please check your e-mails and use the confirmation link.');
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
}
|
||||
|
||||
$user->login($userdata['username']);
|
||||
|
||||
# if user is allowed to view content-area
|
||||
if($this->c->acl->hasRole($userdata['userrole']) && $this->c->acl->isAllowed($userdata['userrole'], 'content', 'view'))
|
||||
{
|
||||
$settings = $this->c->get('settings');
|
||||
$editor = (isset($settings['editor']) && $settings['editor'] == 'visual') ? 'visual' : 'raw';
|
||||
|
||||
return $response->withRedirect($this->c->router->pathFor('content.' . $editor));
|
||||
}
|
||||
return $response->withRedirect($this->c->router->pathFor('user.account'));
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($this->settings['securitylog']) && $this->settings['securitylog'])
|
||||
{
|
||||
\Typemill\Models\Helpers::addLogEntry('wrong login');
|
||||
}
|
||||
|
||||
$this->c->flash->addMessage('error', 'Ups, wrong password or username, please try again.');
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
}
|
||||
}
|
27
system/typemill/Events/BaseEvent.php
Normal file
27
system/typemill/Events/BaseEvent.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
#use Symfony\Component\EventDispatcher\GenericEvent;
|
||||
use Symfony\Contracts\EventDispatcher\Event;
|
||||
|
||||
class BaseEvent extends Event
|
||||
#class BaseEvent extends GenericEvent
|
||||
{
|
||||
protected $data;
|
||||
|
||||
public function __construct($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function setData($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
}
|
14
system/typemill/Events/OnBreadcrumbLoaded.php
Normal file
14
system/typemill/Events/OnBreadcrumbLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for breadcrumb.
|
||||
*/
|
||||
|
||||
class OnBreadcrumbLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnCacheUpdated.php
Normal file
14
system/typemill/Events/OnCacheUpdated.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for the page rendering data.
|
||||
*/
|
||||
|
||||
class OnCacheUpdated extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnContentArrayLoaded.php
Normal file
14
system/typemill/Events/OnContentArrayLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for the page rendering data.
|
||||
*/
|
||||
|
||||
class OnContentArrayLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnHtmlLoaded.php
Normal file
14
system/typemill/Events/OnHtmlLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for html page.
|
||||
*/
|
||||
|
||||
class OnHtmlLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnItemLoaded.php
Normal file
14
system/typemill/Events/OnItemLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for item.
|
||||
*/
|
||||
|
||||
class OnItemLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnMarkdownLoaded.php
Normal file
14
system/typemill/Events/OnMarkdownLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for markdown.
|
||||
*/
|
||||
|
||||
class OnMarkdownLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnMetaDefinitionsLoaded.php
Normal file
14
system/typemill/Events/OnMetaDefinitionsLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for markdown.
|
||||
*/
|
||||
|
||||
class OnMetaDefinitionsLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnMetaLoaded.php
Normal file
14
system/typemill/Events/OnMetaLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for markdown.
|
||||
*/
|
||||
|
||||
class OnMetaLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
35
system/typemill/Events/OnOriginalLoaded.php
Normal file
35
system/typemill/Events/OnOriginalLoaded.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
use Typemill\Extensions\ParsedownExtension;
|
||||
|
||||
/**
|
||||
* Event for html page.
|
||||
*/
|
||||
|
||||
class OnOriginalLoaded extends Event
|
||||
{
|
||||
protected $data;
|
||||
|
||||
public function __construct($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
public function getMarkdown()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function getHTML($urlrel)
|
||||
{
|
||||
$parsedown = new ParsedownExtension();
|
||||
$contentArray = $parsedown->text($this->data);
|
||||
$contentHTML = $parsedown->markup($contentArray, $urlrel);
|
||||
|
||||
return $contentHTML;
|
||||
}
|
||||
}
|
14
system/typemill/Events/OnPageDeleted.php
Normal file
14
system/typemill/Events/OnPageDeleted.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for breadcrumb.
|
||||
*/
|
||||
|
||||
class OnPageDeleted extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnPagePublished.php
Normal file
14
system/typemill/Events/OnPagePublished.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for breadcrumb.
|
||||
*/
|
||||
|
||||
class OnPagePublished extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnPageReady.php
Normal file
14
system/typemill/Events/OnPageReady.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for html data page.
|
||||
*/
|
||||
|
||||
class OnPageReady extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnPageSorted.php
Normal file
14
system/typemill/Events/OnPageSorted.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for breadcrumb.
|
||||
*/
|
||||
|
||||
class OnPageSorted extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnPageUnpublished.php
Normal file
14
system/typemill/Events/OnPageUnpublished.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for breadcrumb.
|
||||
*/
|
||||
|
||||
class OnPageUnpublished extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnPagetreeLoaded.php
Normal file
14
system/typemill/Events/OnPagetreeLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for the page tree.
|
||||
*/
|
||||
|
||||
class OnPagetreeLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnPluginsLoaded.php
Normal file
14
system/typemill/Events/OnPluginsLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for the folder structure.
|
||||
*/
|
||||
|
||||
class OnPluginsLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnResourcesLoaded.php
Normal file
14
system/typemill/Events/OnResourcesLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for acl.
|
||||
*/
|
||||
|
||||
class OnResourcesLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnRestrictionsLoaded.php
Normal file
14
system/typemill/Events/OnRestrictionsLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for page restrictions.
|
||||
*/
|
||||
|
||||
class OnRestrictionsLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnRolesPermissionsLoaded.php
Normal file
14
system/typemill/Events/OnRolesPermissionsLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for acl.
|
||||
*/
|
||||
|
||||
class OnRolesPermissionsLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnSessionSegmentsLoaded.php
Normal file
14
system/typemill/Events/OnSessionSegmentsLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for breadcrumb.
|
||||
*/
|
||||
|
||||
class OnSessionSegmentsLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnSettingsLoaded.php
Normal file
14
system/typemill/Events/OnSettingsLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for settings
|
||||
*/
|
||||
|
||||
class OnSettingsLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnShortcodeFound.php
Normal file
14
system/typemill/Events/OnShortcodeFound.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for breadcrumb.
|
||||
*/
|
||||
|
||||
class OnShortcodeFound extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnSystemnaviLoaded.php
Normal file
14
system/typemill/Events/OnSystemnaviLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for settings
|
||||
*/
|
||||
|
||||
class OnSystemnaviLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnTwigLoaded.php
Normal file
14
system/typemill/Events/OnTwigLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for breadcrumb.
|
||||
*/
|
||||
|
||||
class OnTwigLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnUserConfirmed.php
Normal file
14
system/typemill/Events/OnUserConfirmed.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for the page tree.
|
||||
*/
|
||||
|
||||
class OnUserConfirmed extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnUserDeleted.php
Normal file
14
system/typemill/Events/OnUserDeleted.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for the page tree.
|
||||
*/
|
||||
|
||||
class OnUserDeleted extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
14
system/typemill/Events/OnUserfieldsLoaded.php
Normal file
14
system/typemill/Events/OnUserfieldsLoaded.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for the page tree.
|
||||
*/
|
||||
|
||||
class OnUserfieldsLoaded extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
30
system/typemill/Extensions/TwigCsrfExtension.php
Normal file
30
system/typemill/Extensions/TwigCsrfExtension.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Extensions;
|
||||
|
||||
use Slim\Csrf\Guard;
|
||||
|
||||
class TwigCsrfExtension extends \Twig\Extension\AbstractExtension
|
||||
{
|
||||
protected $csrf;
|
||||
|
||||
public function __construct(Guard $csrf)
|
||||
{
|
||||
$this->csrf = $csrf;
|
||||
}
|
||||
|
||||
public function getFunctions()
|
||||
{
|
||||
return [
|
||||
new \Twig\TwigFunction('csrf', [$this, 'csrf'])
|
||||
];
|
||||
}
|
||||
|
||||
public function csrf()
|
||||
{
|
||||
$csrf = '<p>TokenNameValue: '. $this->csrf->getTokenName() .'</p><input type="hidden" name="' . $this->csrf->getTokenNameKey(). '" value="' . $this->csrf->getTokenName() . '">
|
||||
<input type="hidden" name="' . $this->csrf->getTokenValueKey(). '" value="' . $this->csrf->getTokenValue(). '">';
|
||||
|
||||
return $csrf;
|
||||
}
|
||||
}
|
56
system/typemill/Middleware/CreateSession.php
Normal file
56
system/typemill/Middleware/CreateSession.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Middleware;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||
use Slim\Routing\RouteContext;
|
||||
|
||||
class CreateSession implements MiddlewareInterface
|
||||
{
|
||||
protected $sessionSegments = [];
|
||||
|
||||
protected $routepath = false;
|
||||
|
||||
public function __construct($session_segments, $routepath)
|
||||
{
|
||||
$this->sessionSegments = $session_segments;
|
||||
|
||||
$this->routepath = $routepath;
|
||||
}
|
||||
|
||||
public function process(Request $request, RequestHandler $handler) :response
|
||||
{
|
||||
foreach($this->sessionSegments as $segment)
|
||||
{
|
||||
if(substr( $this->routepath, 0, strlen($segment) ) === ltrim($segment, '/'))
|
||||
{
|
||||
echo '<br>Create Session';
|
||||
|
||||
// configure session
|
||||
ini_set('session.cookie_httponly', 1 );
|
||||
ini_set('session.use_strict_mode', 1);
|
||||
ini_set('session.cookie_samesite', 'lax');
|
||||
/*
|
||||
if($uri->getScheme() == 'https')
|
||||
{
|
||||
ini_set('session.cookie_secure', 1);
|
||||
session_name('__Secure-typemill-session');
|
||||
}
|
||||
else
|
||||
{
|
||||
session_name('typemill-session');
|
||||
}
|
||||
*/
|
||||
// start session
|
||||
session_start();
|
||||
|
||||
$request = $request->withAttribute('session', $_SESSION);
|
||||
}
|
||||
}
|
||||
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
41
system/typemill/Middleware/CsrfProtection.php
Normal file
41
system/typemill/Middleware/CsrfProtection.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Middleware;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Slim\Routing\RouteContext;
|
||||
use Slim\Csrf\Guard;
|
||||
|
||||
class CsrfProtection implements MiddlewareInterface
|
||||
{
|
||||
protected $container;
|
||||
|
||||
protected $responseFactory;
|
||||
|
||||
public function __construct($container, $responseFactory)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->responseFactory = $responseFactory;
|
||||
}
|
||||
|
||||
public function process(Request $request, RequestHandler $handler) :response
|
||||
{
|
||||
if(is_array($request->getAttribute('session')))
|
||||
{
|
||||
echo '<br> csrf protection';
|
||||
|
||||
$responseFactory = $this->responseFactory;
|
||||
|
||||
# Register Middleware On Container
|
||||
$this->container->set('csrf', function () use ($responseFactory)
|
||||
{
|
||||
return new Guard($responseFactory);
|
||||
});
|
||||
}
|
||||
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
30
system/typemill/Middleware/CsrfProtectionToMiddleware.php
Normal file
30
system/typemill/Middleware/CsrfProtectionToMiddleware.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Middleware;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Slim\Routing\RouteContext;
|
||||
use Slim\Csrf\Guard;
|
||||
|
||||
class CsrfProtectionToMiddleware
|
||||
{
|
||||
protected $container;
|
||||
|
||||
public function __construct($container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function __invoke(Request $request, RequestHandler $handler)
|
||||
{
|
||||
if(is_array($request->getAttribute('session')))
|
||||
{
|
||||
echo '<br> csrf protection to middleware';
|
||||
|
||||
return $this->container->get('csrf');
|
||||
}
|
||||
}
|
||||
}
|
34
system/typemill/Middleware/FlashMessages.php
Normal file
34
system/typemill/Middleware/FlashMessages.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Middleware;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Slim\Flash\Messages;
|
||||
|
||||
class FlashMessages implements MiddlewareInterface
|
||||
{
|
||||
|
||||
protected $container;
|
||||
|
||||
public function __construct($container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function process(Request $request, RequestHandler $handler) :response
|
||||
{
|
||||
if(is_array($request->getAttribute('session')))
|
||||
{
|
||||
echo '<br> flash messages';
|
||||
|
||||
$this->container->set('flash', function(){
|
||||
return new Messages();
|
||||
});
|
||||
}
|
||||
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
29
system/typemill/Middleware/JsonBodyParser.php
Normal file
29
system/typemill/Middleware/JsonBodyParser.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Middleware;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
|
||||
class JsonBodyParser implements MiddlewareInterface
|
||||
{
|
||||
public function process(Request $request, RequestHandler $handler) :response
|
||||
{
|
||||
echo '<br> JSON Body parser';
|
||||
|
||||
$contentType = $request->getHeaderLine('Content-Type');
|
||||
|
||||
if (strstr($contentType, 'application/json'))
|
||||
{
|
||||
$contents = json_decode(file_get_contents('php://input'), true);
|
||||
if (json_last_error() === JSON_ERROR_NONE)
|
||||
{
|
||||
$request = $request->withParsedBody($contents);
|
||||
}
|
||||
}
|
||||
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
34
system/typemill/Middleware/RedirectIfAuthenticated.php
Normal file
34
system/typemill/Middleware/RedirectIfAuthenticated.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Middleware;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
# use Slim\Routing\RouteContext;
|
||||
use Slim\Routing\RouteParser;
|
||||
|
||||
class RedirectIfAuthenticated implements MiddlewareInterface
|
||||
{
|
||||
public function __construct(RouteParser $router, $settings)
|
||||
{
|
||||
$this->router = $router;
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
public function process(Request $request, RequestHandler $handler) :response
|
||||
{
|
||||
$response = $handler->handle($request);
|
||||
|
||||
$editor = (isset($this->settings['editor']) && $this->settings['editor'] == 'visual') ? 'visual' : 'raw';
|
||||
|
||||
if(isset($_SESSION['login']))
|
||||
{
|
||||
return $response->withHeader('Location', $this->router->pathFor('content.' . $editor))->withStatus(302);
|
||||
# $response = $response->withRedirect($this->router->pathFor('content.' . $editor));
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
333
system/typemill/Plugin.php
Normal file
333
system/typemill/Plugin.php
Normal file
@@ -0,0 +1,333 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill;
|
||||
|
||||
use \Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Typemill\Models\Fields;
|
||||
use Typemill\Models\WriteYaml;
|
||||
use Typemill\Models\Validation;
|
||||
use Typemill\Extensions\ParsedownExtension;
|
||||
|
||||
abstract class Plugin implements EventSubscriberInterface
|
||||
{
|
||||
protected $container;
|
||||
|
||||
protected $path;
|
||||
|
||||
protected $adminpath = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
|
||||
public function __construct($container)
|
||||
{
|
||||
$this->container = $container;
|
||||
/*
|
||||
$this->path = trim($this->container['request']->getUri()->getPath(),"/");
|
||||
|
||||
if(substr($this->path, 0, 3) === "tm/")
|
||||
{
|
||||
$this->adminpath = true;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
protected function isXhr()
|
||||
{
|
||||
if($this->container['request']->isXhr())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function getParams()
|
||||
{
|
||||
return $this->container['request']->getParams();
|
||||
}
|
||||
|
||||
protected function returnJson($data)
|
||||
{
|
||||
return $this->container['response']
|
||||
->withHeader("Content-Type", "application/json")
|
||||
->withStatus(200)
|
||||
->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
}
|
||||
|
||||
protected function returnJsonError($data)
|
||||
{
|
||||
return $this->container['response']
|
||||
->withHeader("Content-Type", "application/json")
|
||||
->withStatus(400)
|
||||
->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
}
|
||||
|
||||
protected function getSettings()
|
||||
{
|
||||
return $this->container->get('settings');
|
||||
}
|
||||
|
||||
protected function getPluginSettings($plugin)
|
||||
{
|
||||
return $this->container->get('settings')['plugins'][$plugin];
|
||||
}
|
||||
|
||||
protected function getRoute()
|
||||
{
|
||||
return $this->container['request']->getUri()->withUserInfo('');
|
||||
}
|
||||
|
||||
protected function getPath()
|
||||
{
|
||||
return $this->container['request']->getUri()->getPath();
|
||||
}
|
||||
|
||||
protected function getDispatcher()
|
||||
{
|
||||
return $this->container['dispatcher'];
|
||||
}
|
||||
|
||||
protected function getTwig()
|
||||
{
|
||||
return $this->container['view'];
|
||||
}
|
||||
|
||||
protected function addTwigGlobal($name, $class)
|
||||
{
|
||||
$this->container->view->getEnvironment()->addGlobal($name, $class);
|
||||
}
|
||||
|
||||
protected function addTwigFilter($name, $filter)
|
||||
{
|
||||
$filter = new \Twig_SimpleFilter($name, $filter);
|
||||
$this->container->view->getEnvironment()->addFilter($filter);
|
||||
}
|
||||
|
||||
protected function addTwigFunction($name, $function)
|
||||
{
|
||||
$function = new \Twig_SimpleFunction($name, $function);
|
||||
$this->container->view->getEnvironment()->addFunction($function);
|
||||
}
|
||||
|
||||
protected function addJS($JS)
|
||||
{
|
||||
$this->container->assets->addJS($JS);
|
||||
}
|
||||
|
||||
protected function addEditorJS($JS)
|
||||
{
|
||||
$this->container->assets->addEditorJS($JS);
|
||||
}
|
||||
|
||||
protected function addInlineJS($JS)
|
||||
{
|
||||
$this->container->assets->addInlineJS($JS);
|
||||
}
|
||||
|
||||
protected function addSvgSymbol($symbol)
|
||||
{
|
||||
$this->container->assets->addSvgSymbol($symbol);
|
||||
}
|
||||
|
||||
protected function addEditorInlineJS($JS)
|
||||
{
|
||||
$this->container->assets->addEditorInlineJS($JS);
|
||||
}
|
||||
|
||||
protected function addCSS($CSS)
|
||||
{
|
||||
$this->container->assets->addCSS($CSS);
|
||||
}
|
||||
|
||||
protected function addInlineCSS($CSS)
|
||||
{
|
||||
$this->container->assets->addInlineCSS($CSS);
|
||||
}
|
||||
|
||||
protected function addEditorCSS($CSS)
|
||||
{
|
||||
$this->container->assets->addEditorCSS($CSS);
|
||||
}
|
||||
|
||||
protected function getMeta()
|
||||
{
|
||||
return $this->container->assets->meta;
|
||||
}
|
||||
|
||||
public function addMeta($key,$meta)
|
||||
{
|
||||
$this->container->assets->addMeta($key, $meta);
|
||||
}
|
||||
|
||||
protected function activateAxios()
|
||||
{
|
||||
$this->container->assets->activateAxios();
|
||||
}
|
||||
|
||||
protected function activateVue()
|
||||
{
|
||||
$this->container->assets->activateVue();
|
||||
}
|
||||
|
||||
protected function activateTachyons()
|
||||
{
|
||||
$this->container->assets->activateTachyons();
|
||||
}
|
||||
|
||||
protected function markdownToHtml($markdown)
|
||||
{
|
||||
$parsedown = new ParsedownExtension();
|
||||
|
||||
$contentArray = $parsedown->text($markdown);
|
||||
$html = $parsedown->markup($contentArray);
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
protected function getFormData($pluginName)
|
||||
{
|
||||
$flash = $this->container->flash->getMessages();
|
||||
|
||||
if(isset($flash['formdata']))
|
||||
{
|
||||
$yaml = new Models\WriteYaml();
|
||||
$formdata = $yaml->getYaml('settings', 'formdata.yaml');
|
||||
$yaml->updateYaml('settings', 'formdata.yaml', '');
|
||||
|
||||
if($flash['formdata'][0] == $pluginName && isset($formdata[$pluginName]))
|
||||
{
|
||||
return $formdata[$pluginName];
|
||||
}
|
||||
}
|
||||
elseif(isset($flash['publicform']) && $flash['publicform'][0] == 'bot')
|
||||
{
|
||||
return 'bot';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function generateForm($pluginName, $routename)
|
||||
{
|
||||
$fieldsModel = new Fields();
|
||||
|
||||
$settings = $this->getSettings();
|
||||
$form = false;
|
||||
|
||||
$pluginDefinitions = \Typemill\Settings::getObjectSettings('plugins', $pluginName);
|
||||
if(isset($settings['plugins'][$pluginName]['publicformdefinitions']) && $settings['plugins'][$pluginName]['publicformdefinitions'] != '')
|
||||
{
|
||||
$arrayFromYaml = \Symfony\Component\Yaml\Yaml::parse($settings['plugins'][$pluginName]['publicformdefinitions']);
|
||||
$pluginDefinitions['public']['fields'] = $arrayFromYaml;
|
||||
}
|
||||
|
||||
$buttonlabel = isset($settings['plugins'][$pluginName]['button_label']) ? $settings['plugins'][$pluginName]['button_label'] : false;
|
||||
$captchaoptions = isset($settings['plugins'][$pluginName]['captchaoptions']) ? $settings['plugins'][$pluginName]['captchaoptions'] : false;
|
||||
$recaptcha = isset($settings['plugins'][$pluginName]['recaptcha']) ? $settings['plugins'][$pluginName]['recaptcha_webkey'] : false;
|
||||
|
||||
if($captchaoptions == 'disabled')
|
||||
{
|
||||
# in case a captcha has failed on another page like login, the captcha-session must be deleted, otherwise it will not pass the security middleware
|
||||
unset($_SESSION['captcha']);
|
||||
}
|
||||
|
||||
$fieldsModel = new Fields();
|
||||
|
||||
if(isset($pluginDefinitions['public']['fields']))
|
||||
{
|
||||
# get all the fields and prefill them with the dafault-data, the user-data or old input data
|
||||
$fields = $fieldsModel->getFields($settings, 'plugins', $pluginName, $pluginDefinitions, 'public');
|
||||
|
||||
# get Twig Instance
|
||||
$twig = $this->getTwig();
|
||||
|
||||
# render each field and add it to the form
|
||||
$form = $twig->fetch('/partials/form.twig', [
|
||||
'routename' => $routename,
|
||||
'fields' => $fields,
|
||||
'itemName' => $pluginName,
|
||||
'object' => 'plugins',
|
||||
'buttonlabel' => $buttonlabel,
|
||||
'captchaoptions' => $captchaoptions,
|
||||
'recaptcha_webkey' => $recaptcha,
|
||||
]);
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
protected function validateParams($params)
|
||||
{
|
||||
$pluginName = key($params);
|
||||
|
||||
if(isset($params[$pluginName]))
|
||||
{
|
||||
$userInput = $params[$pluginName];
|
||||
$settings = $this->getSettings();
|
||||
|
||||
# get settings and start validation
|
||||
$originalSettings = \Typemill\Settings::getObjectSettings('plugins', $pluginName);
|
||||
if(isset($settings['plugins'][$pluginName]['publicformdefinitions']) && $settings['plugins'][$pluginName]['publicformdefinitions'] != '')
|
||||
{
|
||||
$arrayFromYaml = \Symfony\Component\Yaml\Yaml::parse($settings['plugins'][$pluginName]['publicformdefinitions']);
|
||||
$originalSettings['public']['fields'] = $arrayFromYaml;
|
||||
}
|
||||
elseif(isset($originalSettings['settings']['publicformdefinitions']))
|
||||
{
|
||||
$arrayFromYaml = \Symfony\Component\Yaml\Yaml::parse($originalSettings['settings']['publicformdefinitions']);
|
||||
$originalSettings['public']['fields'] = $arrayFromYaml;
|
||||
}
|
||||
|
||||
$validate = new Validation();
|
||||
|
||||
if(isset($originalSettings['public']['fields']))
|
||||
{
|
||||
# flaten the multi-dimensional array with fieldsets to a one-dimensional array
|
||||
$originalFields = array();
|
||||
foreach($originalSettings['public']['fields'] as $fieldName => $fieldValue)
|
||||
{
|
||||
if(isset($fieldValue['fields']))
|
||||
{
|
||||
foreach($fieldValue['fields'] as $subFieldName => $subFieldValue)
|
||||
{
|
||||
$originalFields[$subFieldName] = $subFieldValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$originalFields[$fieldName] = $fieldValue;
|
||||
}
|
||||
}
|
||||
|
||||
# take the user input data and iterate over all fields and values
|
||||
foreach($userInput as $fieldName => $fieldValue)
|
||||
{
|
||||
# get the corresponding field definition from original plugin settings
|
||||
$fieldDefinition = isset($originalFields[$fieldName]) ? $originalFields[$fieldName] : false;
|
||||
|
||||
if($fieldDefinition)
|
||||
{
|
||||
# validate user input for this field
|
||||
$validate->objectField($fieldName, $fieldValue, $pluginName, $fieldDefinition);
|
||||
}
|
||||
if(!$fieldDefinition && $fieldName != 'active')
|
||||
{
|
||||
$_SESSION['errors'][$pluginName][$fieldName] = array('This field is not defined!');
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($_SESSION['errors']))
|
||||
{
|
||||
$this->container->flash->addMessage('error', 'Please correct the errors');
|
||||
return false;
|
||||
}
|
||||
|
||||
return $params[$pluginName];
|
||||
}
|
||||
}
|
||||
|
||||
$this->container->flash->addMessage('error', 'The data from the form was invalid (missing or not defined)');
|
||||
return false;
|
||||
}
|
||||
}
|
27
system/typemill/Static/Helpers.php
Normal file
27
system/typemill/Static/Helpers.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Static;
|
||||
|
||||
class Helpers{
|
||||
|
||||
public static function printTimer($timer)
|
||||
{
|
||||
$lastTime = NULL;
|
||||
$table = '<html><body><table>';
|
||||
$table .= '<tr><th>Breakpoint</th><th>Time</th><th>Duration</th></tr>';
|
||||
foreach($timer as $breakpoint => $time)
|
||||
{
|
||||
$duration = $time - $lastTime;
|
||||
|
||||
$table .= '<tr>';
|
||||
$table .= '<td>' . $breakpoint . '</td>';
|
||||
$table .= '<td>' . $time . '</td>';
|
||||
$table .= '<td>' . $duration . '</td>';
|
||||
$table .= '</tr>';
|
||||
|
||||
$lastTime = $time;
|
||||
}
|
||||
$table .= '</table></body></html>';
|
||||
echo $table;
|
||||
}
|
||||
}
|
24
system/typemill/Static/Languages.php
Normal file
24
system/typemill/Static/Languages.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Static;
|
||||
|
||||
class Languages
|
||||
{
|
||||
public static function whichLanguage()
|
||||
{
|
||||
# Check which languages are available
|
||||
$langs = [];
|
||||
$path = __DIR__ . '/author/languages/*.yaml';
|
||||
|
||||
foreach (glob($path) as $filename)
|
||||
{
|
||||
$langs[] = basename($filename,'.yaml');
|
||||
}
|
||||
|
||||
# Detect browser language
|
||||
$accept_lang = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2) : false;
|
||||
$lang = in_array($accept_lang, $langs) ? $accept_lang : 'en';
|
||||
|
||||
return $lang;
|
||||
}
|
||||
}
|
68
system/typemill/Static/Permissions.php
Normal file
68
system/typemill/Static/Permissions.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Static;
|
||||
|
||||
use Laminas\Permissions\Acl\Acl;
|
||||
use Laminas\Permissions\Acl\Role\GenericRole as Role;
|
||||
use Laminas\Permissions\Acl\Resource\GenericResource as Resource;
|
||||
|
||||
class Permissions
|
||||
{
|
||||
public static function loadResources($defaultsettingspath)
|
||||
{
|
||||
$resourcesfile = $defaultsettingspath . 'resources.yaml';
|
||||
|
||||
if(file_exists($resourcesfile))
|
||||
{
|
||||
$resourcesyaml = file_get_contents($resourcesfile);
|
||||
$resources = \Symfony\Component\Yaml\Yaml::parse($resourcesyaml);
|
||||
|
||||
return $resources;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function loadRolesAndPermissions($defaultsettingspath)
|
||||
{
|
||||
|
||||
$permissionsfile = $defaultsettingspath . 'permissions.yaml';
|
||||
|
||||
if(file_exists($permissionsfile))
|
||||
{
|
||||
$permissionsyaml = file_get_contents($permissionsfile);
|
||||
$permissions = \Symfony\Component\Yaml\Yaml::parse($permissionsyaml);
|
||||
|
||||
return $permissions;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function createAcl($roles, $resources)
|
||||
{
|
||||
$acl = new Acl();
|
||||
|
||||
foreach($resources as $resource)
|
||||
{
|
||||
$acl->addResource(new Resource($resource));
|
||||
}
|
||||
|
||||
# add all other roles dynamically
|
||||
foreach($roles as $role)
|
||||
{
|
||||
$acl->addRole(new Role($role['name']), $role['inherits']);
|
||||
|
||||
foreach($role['permissions'] as $resource => $permissions)
|
||||
{
|
||||
$acl->allow($role['name'], $resource, $permissions);
|
||||
}
|
||||
}
|
||||
|
||||
# add administrator role
|
||||
$acl->addRole(new Role('administrator'));
|
||||
$acl->allow('administrator');
|
||||
|
||||
return $acl;
|
||||
}
|
||||
}
|
112
system/typemill/Static/Plugins.php
Normal file
112
system/typemill/Static/Plugins.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Static;
|
||||
|
||||
class Plugins
|
||||
{
|
||||
public static function loadPlugins($rootpath)
|
||||
{
|
||||
$pluginFolder = self::scanPluginFolder($rootpath);
|
||||
$classNames = [];
|
||||
|
||||
# iterate over plugin folders
|
||||
foreach($pluginFolder as $plugin)
|
||||
{
|
||||
$className = '\\Plugins\\' . $plugin . '\\' . $plugin;
|
||||
|
||||
# if plugin-class exists, add classname to array
|
||||
if(class_exists($className))
|
||||
{
|
||||
$classNames[] = ['className' => $className, 'name' => $plugin];
|
||||
}
|
||||
}
|
||||
|
||||
return $classNames;
|
||||
}
|
||||
|
||||
public static function scanPluginFolder($rootpath)
|
||||
{
|
||||
$pluginsDir = $rootpath . '/plugins';
|
||||
|
||||
# check if plugins directory exists
|
||||
if(!is_dir($pluginsDir)){ return array(); }
|
||||
|
||||
# get all plugin folders
|
||||
$plugins = array_diff(scandir($pluginsDir), array('..', '.'));
|
||||
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
public static function getNewRoutes($className, $routes)
|
||||
{
|
||||
# if route-method exists in plugin-class
|
||||
if(method_exists($className, 'addNewRoutes'))
|
||||
{
|
||||
# add the routes
|
||||
$pluginRoutes = $className::addNewRoutes();
|
||||
|
||||
# multi-dimensional or simple array of routes
|
||||
if(isset($pluginRoutes[0]))
|
||||
{
|
||||
# if they are properly formatted, add them to routes array
|
||||
foreach($pluginRoutes as $pluginRoute)
|
||||
{
|
||||
if(self::checkRouteArray($routes,$pluginRoute))
|
||||
{
|
||||
$pluginRoute['route'] = strtolower($pluginRoute['route']);
|
||||
$routes[] = $pluginRoute;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif(is_array($routes))
|
||||
{
|
||||
if(self::checkRouteArray($routes,$pluginRoutes))
|
||||
{
|
||||
$pluginRoutes['route'] = strtolower($pluginRoutes['route']);
|
||||
$routes[] = $pluginRoutes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $routes;
|
||||
}
|
||||
|
||||
public static function getNewMiddleware($className, $middleware)
|
||||
{
|
||||
if(method_exists($className, 'addNewMiddleware'))
|
||||
{
|
||||
$pluginMiddleware = $className::addNewMiddleware();
|
||||
|
||||
if($pluginMiddleware)
|
||||
{
|
||||
$middleware[] = $pluginMiddleware;
|
||||
}
|
||||
}
|
||||
|
||||
return $middleware;
|
||||
}
|
||||
|
||||
private static function checkRouteArray($routes,$route)
|
||||
{
|
||||
if(
|
||||
isset($route['httpMethod']) AND in_array($route['httpMethod'], array('get','post','put','delete','head','patch','options'))
|
||||
AND isset($route['route']) AND is_string($route['route'])
|
||||
AND isset($route['class']) AND is_string($route['class']))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function in_array_r($needle, $haystack, $strict = false)
|
||||
{
|
||||
foreach ($haystack as $item)
|
||||
{
|
||||
if (($strict ? $item === $needle : $item == $needle) || (is_array($item) && $this->in_array_r($needle, $item, $strict)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
43
system/typemill/Static/Session.php
Normal file
43
system/typemill/Static/Session.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Static;
|
||||
|
||||
class Session
|
||||
{
|
||||
public static function startSessionForSegments($sessionSegments, $routepath)
|
||||
{
|
||||
$routepath = ltrim($routepath, '/');
|
||||
|
||||
foreach($sessionSegments as $segment)
|
||||
{
|
||||
echo '<br>' . $segment;
|
||||
echo '<br>' . $routepath;
|
||||
if(substr( $routepath, 0, strlen($segment) ) === ltrim($segment, '/'))
|
||||
{
|
||||
echo '<br>Create Session';
|
||||
|
||||
# configure session
|
||||
ini_set('session.cookie_httponly', 1 );
|
||||
ini_set('session.use_strict_mode', 1);
|
||||
ini_set('session.cookie_samesite', 'lax');
|
||||
|
||||
/*
|
||||
if($uri->getScheme() == 'https')
|
||||
{
|
||||
ini_set('session.cookie_secure', 1);
|
||||
session_name('__Secure-typemill-session');
|
||||
}
|
||||
else
|
||||
{
|
||||
session_name('typemill-session');
|
||||
}
|
||||
*/
|
||||
|
||||
# start session
|
||||
session_start();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
202
system/typemill/Static/Settings.php
Normal file
202
system/typemill/Static/Settings.php
Normal file
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Static;
|
||||
|
||||
class Settings
|
||||
{
|
||||
public static function loadSettings($rootpath)
|
||||
{
|
||||
$defaultsettings = self::getDefaultSettings($rootpath);
|
||||
$usersettings = self::getUserSettings($rootpath);
|
||||
|
||||
$settings = $defaultsettings;
|
||||
|
||||
if($usersettings)
|
||||
{
|
||||
$settings = array_merge($defaultsettings, $usersettings);
|
||||
|
||||
# make sure all image-size information are there
|
||||
if(isset($usersettings['images']))
|
||||
{
|
||||
$images = array_merge($defaultsettings['images'], $settings['images']);
|
||||
$settings['images'] = $images;
|
||||
}
|
||||
}
|
||||
|
||||
$settings = self::addThemeSettings($settings);
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
public static function addThemeSettings($settings)
|
||||
{
|
||||
# we have to check if the theme has been deleted
|
||||
$themefolder = $settings['rootPath'] . DIRECTORY_SEPARATOR . $settings['themeFolder'] . DIRECTORY_SEPARATOR;
|
||||
|
||||
# if there is no theme in settings or theme has been deleted
|
||||
if(!isset($settings['theme']) OR !file_exists($themefolder . $settings['theme']))
|
||||
{
|
||||
# scan theme folder and get the first theme
|
||||
$themes = array_filter(scandir($themefolder), function ($item) use($themefolder)
|
||||
{
|
||||
return is_dir($themefolder . $item) && strpos($item, '.') !== 0;
|
||||
});
|
||||
|
||||
$firsttheme = reset($themes);
|
||||
|
||||
# if there is a theme with an index.twig-file
|
||||
if($firsttheme && file_exists($themefolder . $firsttheme . DIRECTORY_SEPARATOR . 'index.twig'))
|
||||
{
|
||||
$settings['theme'] = $firsttheme;
|
||||
}
|
||||
else
|
||||
{
|
||||
die('You need at least one theme with an index.twig-file in your theme-folder.');
|
||||
}
|
||||
}
|
||||
|
||||
# We have the theme so create the theme path
|
||||
$settings['themePath'] = $settings['rootPath'] . $settings['themeFolder'] . DIRECTORY_SEPARATOR . $settings['theme'];
|
||||
|
||||
# if there are no theme settings yet (e.g. no setup yet) use default theme settings
|
||||
if(!isset($settings['themes']))
|
||||
{
|
||||
$themeSettings = self::getObjectSettings('themes', $settings['theme']);
|
||||
$settings['themes'][$settings['theme']] = isset($themeSettings['settings']) ? $themeSettings['settings'] : false;
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
public static function getDefaultSettings($rootpath)
|
||||
{
|
||||
$defaultsettingspath = $rootpath . DIRECTORY_SEPARATOR . 'system' . DIRECTORY_SEPARATOR . 'typemill' . DIRECTORY_SEPARATOR . 'settings' . DIRECTORY_SEPARATOR;
|
||||
$defaultsettingsfile = $defaultsettingspath . 'defaults.yaml';
|
||||
|
||||
if(file_exists($defaultsettingsfile))
|
||||
{
|
||||
$defaultsettingsyaml = file_get_contents($defaultsettingsfile);
|
||||
$defaultsettings = \Symfony\Component\Yaml\Yaml::parse($defaultsettingsyaml);
|
||||
$defaultsettings['rootPath'] = $rootpath;
|
||||
$defaultsettings['defaultSettingsPath'] = $defaultsettingspath;
|
||||
|
||||
return $defaultsettings;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function getUserSettings($rootpath)
|
||||
{
|
||||
$usersettingsfile = $rootpath . DIRECTORY_SEPARATOR . 'settings' . DIRECTORY_SEPARATOR . 'settings.yaml';
|
||||
|
||||
if(file_exists($usersettingsfile))
|
||||
{
|
||||
$usersettingsyaml = file_get_contents($usersettingsfile);
|
||||
$usersettings = \Symfony\Component\Yaml\Yaml::parse($usersettingsyaml);
|
||||
|
||||
return $usersettings;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
### refactor
|
||||
|
||||
|
||||
public static function getObjectSettings($objectType, $objectName)
|
||||
{
|
||||
$yaml = new Models\WriteYaml();
|
||||
|
||||
$objectFolder = $objectType . DIRECTORY_SEPARATOR . $objectName;
|
||||
$objectFile = $objectName . '.yaml';
|
||||
$objectSettings = $yaml->getYaml($objectFolder, $objectFile);
|
||||
|
||||
return $objectSettings;
|
||||
}
|
||||
|
||||
public static function createSettings()
|
||||
{
|
||||
$yaml = new Models\WriteYaml();
|
||||
|
||||
$language = self::whichLanguage();
|
||||
|
||||
# create initial settings file with only setup false
|
||||
if($yaml->updateYaml('settings', 'settings.yaml', array('setup' => false, 'language' => $language)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function updateSettings($settings)
|
||||
{
|
||||
# only allow if usersettings already exists (setup has been done)
|
||||
$userSettings = self::getUserSettings();
|
||||
|
||||
if($userSettings)
|
||||
{
|
||||
# whitelist settings that can be stored in usersettings (values are not relevant here, only keys)
|
||||
$allowedUserSettings = ['displayErrorDetails' => true,
|
||||
'title' => true,
|
||||
'copyright' => true,
|
||||
'language' => true,
|
||||
'langattr' => true,
|
||||
'startpage' => true,
|
||||
'author' => true,
|
||||
'year' => true,
|
||||
'access' => true,
|
||||
'pageaccess' => true,
|
||||
'hrdelimiter' => true,
|
||||
'restrictionnotice' => true,
|
||||
'wraprestrictionnotice' => true,
|
||||
'headlineanchors' => true,
|
||||
'theme' => true,
|
||||
'editor' => true,
|
||||
'formats' => true,
|
||||
'setup' => true,
|
||||
'welcome' => true,
|
||||
'images' => true,
|
||||
'live' => true,
|
||||
'width' => true,
|
||||
'height' => true,
|
||||
'plugins' => true,
|
||||
'themes' => true,
|
||||
'latestVersion' => true,
|
||||
'logo' => true,
|
||||
'favicon' => true,
|
||||
'twigcache' => true,
|
||||
'proxy' => true,
|
||||
'trustedproxies' => true,
|
||||
'headersoff' => true,
|
||||
'urlschemes' => true,
|
||||
'svg' => true,
|
||||
'recoverpw' => true,
|
||||
'recoversubject' => true,
|
||||
'recovermessage' => true,
|
||||
'recoverfrom' => true,
|
||||
'securitylog' => true,
|
||||
'oldslug' => true,
|
||||
'refreshcache' => true,
|
||||
'pingsitemap' => true,
|
||||
];
|
||||
|
||||
# cleanup the existing usersettings
|
||||
$userSettings = array_intersect_key($userSettings, $allowedUserSettings);
|
||||
|
||||
# cleanup the new settings passed as an argument
|
||||
$settings = array_intersect_key($settings, $allowedUserSettings);
|
||||
|
||||
# merge usersettings with new settings
|
||||
$settings = array_merge($userSettings, $settings);
|
||||
|
||||
# write settings to yaml
|
||||
$yaml = new Models\WriteYaml();
|
||||
$yaml->updateYaml('settings', 'settings.yaml', $settings);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
1
system/typemill/author/404.twig
Normal file
1
system/typemill/author/404.twig
Normal file
@@ -0,0 +1 @@
|
||||
404 from author
|
5
system/typemill/author/home.twig
Normal file
5
system/typemill/author/home.twig
Normal file
@@ -0,0 +1,5 @@
|
||||
<h1>Home from Author</h1>
|
||||
|
||||
<h2>{{ title }}</h2>
|
||||
|
||||
<p>{{ description}}</p>
|
56
system/typemill/author/login.twig
Normal file
56
system/typemill/author/login.twig
Normal file
@@ -0,0 +1,56 @@
|
||||
|
||||
{% block title %}Login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="setupWrapper">
|
||||
|
||||
<div class="setupContent">
|
||||
|
||||
</div>
|
||||
<div class="authformWrapper">
|
||||
<form method="POST" action="{{ url_for("auth.login") }}" autocomplete="off">
|
||||
|
||||
<fieldset class="auth">
|
||||
<div class="formElement{{ errors.username ? ' errors' : '' }}">
|
||||
|
||||
<input type="text" name="username" value="{{ old.username }}" required>
|
||||
{% if errors.signup_username %}
|
||||
<span class="error">{{ errors.username | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="formElement{{ errors.password ? ' errors' : '' }}">
|
||||
|
||||
<input type="password" name="password" required autoomplete="off">
|
||||
{% if errors.password %}
|
||||
<span class="error">{{ errors.password | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="personal-mail">
|
||||
<label>Personal Mail</label>
|
||||
<input type="text" name="personal-honey-mail">
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<div class="loginarea" id="loginarea">
|
||||
|
||||
{{ csrf() | raw }}
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% if settings.recoverpw %}
|
||||
|
||||
|
||||
{% else %}
|
||||
|
||||
<div class="setupContent">
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
<footer></footer>
|
||||
{% endblock %}
|
55
system/typemill/routes/api.php
Normal file
55
system/typemill/routes/api.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
use Typemill\Controllers\ControllerAuthorArticleApi;
|
||||
use Typemill\Controllers\ControllerAuthorBlockApi;
|
||||
use Typemill\Controllers\ControllerAuthorMetaApi;
|
||||
use Typemill\Controllers\ControllerAuthorMediaApi;
|
||||
use Typemill\Controllers\ControllerSettings;
|
||||
use Typemill\Middleware\RestrictApiAccess;
|
||||
|
||||
$app->get('/api/v1/themes', ControllerSettings::class . ':getThemeSettings')->setName('api.themes')->add(new RestrictApiAccess($container['router']));
|
||||
$app->delete('/api/v1/clearcache', ControllerSettings::class . ':clearCache')->setName('api.clearcache')->add(new RestrictApiAccess($container['router']));
|
||||
$app->get('/api/v1/users/getbynames', ControllerSettings::class . ':getUsersByNames')->setName('api.usersbynames')->add(new RestrictApiAccess($container['router']));
|
||||
$app->get('/api/v1/users/getbyemail', ControllerSettings::class . ':getUsersByEmail')->setName('api.usersbyemail')->add(new RestrictApiAccess($container['router']));
|
||||
$app->get('/api/v1/users/getbyrole', ControllerSettings::class . ':getUsersByRole')->setName('api.usersbyrole')->add(new RestrictApiAccess($container['router']));
|
||||
|
||||
$app->post('/api/v1/article/markdown', ControllerAuthorArticleApi::class . ':getArticleMarkdown')->setName('api.article.markdown')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/article/html', ControllerAuthorArticleApi::class . ':getArticleHtml')->setName('api.article.html')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/article/publish', ControllerAuthorArticleApi::class . ':publishArticle')->setName('api.article.publish')->add(new RestrictApiAccess($container['router']));
|
||||
$app->delete('/api/v1/article/unpublish', ControllerAuthorArticleApi::class . ':unpublishArticle')->setName('api.article.unpublish')->add(new RestrictApiAccess($container['router']));
|
||||
$app->delete('/api/v1/article/discard', ControllerAuthorArticleApi::class . ':discardArticleChanges')->setName('api.article.discard')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/article/rename', ControllerAuthorArticleApi::class . ':renameArticle')->setName('api.article.rename')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/article/sort', ControllerAuthorArticleApi::class . ':sortArticle')->setName('api.article.sort')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/article', ControllerAuthorArticleApi::class . ':createArticle')->setName('api.article.create')->add(new RestrictApiAccess($container['router']));
|
||||
$app->put('/api/v1/article', ControllerAuthorArticleApi::class . ':updateArticle')->setName('api.article.update')->add(new RestrictApiAccess($container['router']));
|
||||
$app->delete('/api/v1/article', ControllerAuthorArticleApi::class . ':deleteArticle')->setName('api.article.delete')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/baseitem', ControllerAuthorArticleApi::class . ':createBaseItem')->setName('api.baseitem.create')->add(new RestrictApiAccess($container['router']));
|
||||
$app->get('/api/v1/navigation', ControllerAuthorArticleApi::class . ':getNavigation')->setName('api.navigation.get')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/post', ControllerAuthorArticleApi::class . ':createPost')->setName('api.post.create')->add(new RestrictApiAccess($container['router']));
|
||||
|
||||
$app->get('/api/v1/metadefinitions', ControllerAuthorMetaApi::class . ':getMetaDefinitions')->setName('api.metadefinitions.get')->add(new RestrictApiAccess($container['router']));
|
||||
$app->get('/api/v1/article/metaobject', ControllerAuthorMetaApi::class . ':getArticleMetaobject')->setName('api.articlemetaobject.get')->add(new RestrictApiAccess($container['router']));
|
||||
$app->get('/api/v1/article/metadata', ControllerAuthorMetaApi::class . ':getArticleMeta')->setName('api.articlemeta.get')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/article/metadata', ControllerAuthorMetaApi::class . ':updateArticleMeta')->setName('api.articlemeta.update')->add(new RestrictApiAccess($container['router']));
|
||||
|
||||
$app->post('/api/v1/block', ControllerAuthorBlockApi::class . ':addBlock')->setName('api.block.add')->add(new RestrictApiAccess($container['router']));
|
||||
$app->put('/api/v1/block', ControllerAuthorBlockApi::class . ':updateBlock')->setName('api.block.update')->add(new RestrictApiAccess($container['router']));
|
||||
$app->delete('/api/v1/block', ControllerAuthorBlockApi::class . ':deleteBlock')->setName('api.block.delete')->add(new RestrictApiAccess($container['router']));
|
||||
$app->put('/api/v1/moveblock', ControllerAuthorBlockApi::class . ':moveBlock')->setName('api.block.move')->add(new RestrictApiAccess($container['router']));
|
||||
$app->get('/api/v1/shortcodedata', ControllerAuthorBlockApi::class . ':getShortcodeData')->setName('api.shortcodedata.get')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/video', ControllerAuthorMediaApi::class . ':saveVideoImage')->setName('api.video.save')->add(new RestrictApiAccess($container['router']));
|
||||
|
||||
$app->get('/api/v1/medialib/images', ControllerAuthorMediaApi::class . ':getMediaLibImages')->setName('api.medialibimg.get')->add(new RestrictApiAccess($container['router']));
|
||||
$app->get('/api/v1/medialib/files', ControllerAuthorMediaApi::class . ':getMediaLibFiles')->setName('api.medialibfiles.get')->add(new RestrictApiAccess($container['router']));
|
||||
$app->get('/api/v1/image', ControllerAuthorMediaApi::class . ':getImage')->setName('api.image.get')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/image', ControllerAuthorMediaApi::class . ':createImage')->setName('api.image.create')->add(new RestrictApiAccess($container['router']));
|
||||
$app->put('/api/v1/image', ControllerAuthorMediaApi::class . ':publishImage')->setName('api.image.publish')->add(new RestrictApiAccess($container['router']));
|
||||
$app->delete('/api/v1/image', ControllerAuthorMediaApi::class . ':deleteImage')->setName('api.image.delete')->add(new RestrictApiAccess($container['router']));
|
||||
$app->get('/api/v1/filerestrictions', ControllerAuthorMediaApi::class . ':getFileRestrictions')->setName('api.file.getrestrictions')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/filerestrictions', ControllerAuthorMediaApi::class . ':updateFileRestrictions')->setName('api.file.updaterestrictions')->add(new RestrictApiAccess($container['router']));
|
||||
$app->get('/api/v1/file', ControllerAuthorMediaApi::class . ':getFile')->setName('api.file.get')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/file', ControllerAuthorMediaApi::class . ':uploadFile')->setName('api.file.upload')->add(new RestrictApiAccess($container['router']));
|
||||
$app->put('/api/v1/file', ControllerAuthorMediaApi::class . ':publishFile')->setName('api.file.publish')->add(new RestrictApiAccess($container['router']));
|
||||
$app->delete('/api/v1/file', ControllerAuthorMediaApi::class . ':deleteFile')->setName('api.file.delete')->add(new RestrictApiAccess($container['router']));
|
||||
*/
|
112
system/typemill/routes/web.php
Normal file
112
system/typemill/routes/web.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
use Typemill\Controllers\ControllerWebFrontend;
|
||||
use Typemill\Controllers\ControllerWebLogin;
|
||||
use Typemill\Middleware\RedirectIfUnauthenticated;
|
||||
use Typemill\Middleware\RedirectIfAuthenticated;
|
||||
use Slim\Views\TwigMiddleware;
|
||||
|
||||
|
||||
$app->get('/tm/login', ControllerWebLogin::class . ':show')->setName('auth.show')
|
||||
->add(new RedirectIfAuthenticated($container->get('routeParser'), $container->get('settings')))
|
||||
->add(TwigMiddleware::createFromContainer($app));
|
||||
#$app->post('/tm/login', ControllerWebLogin::class . ':login')->setName('auth.login')->add(new RedirectIfAuthenticated($container['router'], $container['settings']));
|
||||
$app->get('/[{params:.*}]', ControllerWebFrontend::class . ':index')->setName('home');
|
||||
|
||||
/*
|
||||
use Typemill\Controllers\ControllerAuthorEditor;
|
||||
use Typemill\Controllers\ControllerSettings;
|
||||
use Typemill\Controllers\ControllerDownload;
|
||||
use Typemill\Controllers\ControllerFrontendForms;
|
||||
use Typemill\Controllers\ControllerFrontendAuth;
|
||||
use Typemill\Controllers\ControllerFrontendSetup;
|
||||
use Typemill\Middleware\RedirectIfNoAdmin;
|
||||
use Typemill\Middleware\accessMiddleware;
|
||||
|
||||
if($settings['settings']['setup'])
|
||||
{
|
||||
$app->get('/setup', ControllerFrontendSetup::class . ':show')->setName('setup.show');
|
||||
$app->post('/setup', ControllerFrontendSetup::class . ':create')->setName('setup.create');
|
||||
}
|
||||
else
|
||||
{
|
||||
$app->get('/setup', ControllerFrontendAuth::class . ':redirect');
|
||||
}
|
||||
if($settings['settings']['welcome'])
|
||||
{
|
||||
$app->get('/setup/welcome', ControllerFrontendSetup::class . ':welcome')->setName('setup.welcome')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
}
|
||||
else
|
||||
{
|
||||
$app->get('/setup/welcome', ControllerFrontendAuth::class . ':redirect')->setName('setup.welcome');
|
||||
}
|
||||
|
||||
$app->post('/tm/formpost', ControllerFrontendForms::class . ':savePublicForm')->setName('form.save');
|
||||
|
||||
$app->get('/tm', ControllerFrontendAuth::class . ':redirect');
|
||||
$app->get('/tm/login', ControllerFrontendAuth::class . ':show')->setName('auth.show')->add(new RedirectIfAuthenticated($container['router'], $container['settings']));
|
||||
$app->post('/tm/login', ControllerFrontendAuth::class . ':login')->setName('auth.login')->add(new RedirectIfAuthenticated($container['router'], $container['settings']));
|
||||
$app->get('/tm/logout', ControllerFrontendAuth::class . ':logout')->setName('auth.logout')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
|
||||
if(isset($settings['settings']['recoverpw']) && $settings['settings']['recoverpw'])
|
||||
{
|
||||
$app->get('/tm/recoverpw', ControllerFrontendAuth::class . ':showrecoverpassword')->setName('auth.recoverpwshow')->add(new RedirectIfAuthenticated($container['router'], $container['settings']));
|
||||
$app->post('/tm/recoverpw', ControllerFrontendAuth::class . ':recoverpassword')->setName('auth.recoverpw')->add(new RedirectIfAuthenticated($container['router'], $container['settings']));
|
||||
$app->get('/tm/recoverpwnew', ControllerFrontendAuth::class . ':showrecoverpasswordnew')->setName('auth.recoverpwshownew')->add(new RedirectIfAuthenticated($container['router'], $container['settings']));
|
||||
$app->post('/tm/recoverpwnew', ControllerFrontendAuth::class . ':createrecoverpasswordnew')->setName('auth.recoverpwnew')->add(new RedirectIfAuthenticated($container['router'], $container['settings']));
|
||||
}
|
||||
|
||||
$app->get('/tm/settings', ControllerSettings::class . ':showSettings')->setName('settings.show')->add(new accessMiddleware($container['router'], $container['acl'], 'system', 'view'));
|
||||
$app->post('/tm/settings', ControllerSettings::class . ':saveSettings')->setName('settings.save')->add(new accessMiddleware($container['router'], $container['acl'], 'system', 'update'));
|
||||
|
||||
$app->get('/tm/themes', ControllerSettings::class . ':showThemes')->setName('themes.show')->add(new accessMiddleware($container['router'], $container['acl'], 'system', 'view'));
|
||||
$app->post('/tm/themes', ControllerSettings::class . ':saveThemes')->setName('themes.save')->add(new accessMiddleware($container['router'], $container['acl'], 'system', 'update'));
|
||||
|
||||
$app->get('/tm/plugins', ControllerSettings::class . ':showPlugins')->setName('plugins.show')->add(new accessMiddleware($container['router'], $container['acl'], 'system', 'view'));
|
||||
$app->post('/tm/plugins', ControllerSettings::class . ':savePlugins')->setName('plugins.save')->add(new accessMiddleware($container['router'], $container['acl'], 'system', 'update'));
|
||||
|
||||
$app->get('/tm/account', ControllerSettings::class . ':showAccount')->setName('user.account')->add(new accessMiddleware($container['router'], $container['acl'], 'user', 'view'));
|
||||
$app->get('/tm/user/new', ControllerSettings::class . ':newUser')->setName('user.new')->add(new accessMiddleware($container['router'], $container['acl'], 'user', 'create'));
|
||||
$app->post('/tm/user/create', ControllerSettings::class . ':createUser')->setName('user.create')->add(new accessMiddleware($container['router'], $container['acl'], 'user', 'create'));
|
||||
$app->post('/tm/user/update', ControllerSettings::class . ':updateUser')->setName('user.update')->add(new accessMiddleware($container['router'], $container['acl'], 'user', 'update'));
|
||||
$app->post('/tm/user/delete', ControllerSettings::class . ':deleteUser')->setName('user.delete')->add(new accessMiddleware($container['router'], $container['acl'], 'user', 'delete'));
|
||||
$app->get('/tm/user/{username}', ControllerSettings::class . ':showUser')->setName('user.show')->add(new accessMiddleware($container['router'], $container['acl'], 'user', 'view'));
|
||||
$app->get('/tm/users', ControllerSettings::class . ':listUser')->setName('user.list')->add(new accessMiddleware($container['router'], $container['acl'], 'userlist', 'view'));
|
||||
|
||||
$app->get('/tm/content/raw[/{params:.*}]', ControllerAuthorEditor::class . ':showContent')->setName('content.raw')->add(new accessMiddleware($container['router'], $container['acl'], 'content', 'view'));
|
||||
$app->get('/tm/content/visual[/{params:.*}]', ControllerAuthorEditor::class . ':showBlox')->setName('content.visual')->add(new accessMiddleware($container['router'], $container['acl'], 'content', 'view'));
|
||||
$app->get('/tm/content[/{params:.*}]', ControllerAuthorEditor::class . ':showEmpty')->setName('content.empty')->add(new accessMiddleware($container['router'], $container['acl'], 'content', 'view'));
|
||||
|
||||
$app->get('/media/files[/{params:.*}]', ControllerDownload::class . ':download')->setName('download.file');
|
||||
|
||||
foreach($routes as $pluginRoute)
|
||||
{
|
||||
$method = $pluginRoute['httpMethod'];
|
||||
$route = $pluginRoute['route'];
|
||||
$class = $pluginRoute['class'];
|
||||
$resource = isset($pluginRoute['resource']) ? $pluginRoute['resource'] : NULL;
|
||||
$privilege = isset($pluginRoute['privilege']) ? $pluginRoute['privilege'] : NULL;
|
||||
|
||||
if(isset($pluginRoute['name']))
|
||||
{
|
||||
$app->{$method}($route, $class)->setName($pluginRoute['name'])->add(new accessMiddleware($container['router'], $container['acl'], $resource, $privilege));
|
||||
}
|
||||
else
|
||||
{
|
||||
$app->{$method}($route, $class)->add(new accessMiddleware($container['router'], $container['acl'], $resource, $privilege));
|
||||
}
|
||||
}
|
||||
|
||||
if($settings['settings']['setup'])
|
||||
{
|
||||
$app->get('/[{params:.*}]', ControllerFrontendSetup::class . ':redirect');
|
||||
}
|
||||
elseif(isset($settings['settings']['access']) && $settings['settings']['access'] != '')
|
||||
{
|
||||
$app->get('/[{params:.*}]', ControllerFrontendWebsite::class . ':index')->setName('home')->add(new accessMiddleware($container['router'], $container['acl'], 'user', 'view'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$app->get('/[{params:.*}]', ControllerFrontendWebsite::class . ':index')->setName('home');
|
||||
}
|
||||
*/
|
36
system/typemill/settings/defaults.yaml
Normal file
36
system/typemill/settings/defaults.yaml
Normal file
@@ -0,0 +1,36 @@
|
||||
version: '2.0.0'
|
||||
setup: true
|
||||
welcome: true
|
||||
title: 'Typemill'
|
||||
author: 'Unknown'
|
||||
copyright: 'Copyright'
|
||||
language: 'en'
|
||||
langattr: 'en'
|
||||
themeFolder: 'themes'
|
||||
settingsFolder: 'settings'
|
||||
contentFolder: 'content'
|
||||
authorFolder: '/system/typemill/author'
|
||||
adminSegment: 'tm'
|
||||
editor: 'visual'
|
||||
formats:
|
||||
- 'markdown'
|
||||
- 'headline'
|
||||
- 'ulist'
|
||||
- 'olist'
|
||||
- 'table'
|
||||
- 'quote'
|
||||
- 'notice'
|
||||
- 'image'
|
||||
- 'video'
|
||||
- 'file'
|
||||
- 'toc'
|
||||
- 'hr'
|
||||
- 'definition'
|
||||
- 'code'
|
||||
- 'shortcode'
|
||||
images:
|
||||
live:
|
||||
width: 820
|
||||
thumbs:
|
||||
width: 250
|
||||
height: 150
|
104
system/typemill/settings/metatabs.yaml
Normal file
104
system/typemill/settings/metatabs.yaml
Normal file
@@ -0,0 +1,104 @@
|
||||
meta:
|
||||
fields:
|
||||
navtitle:
|
||||
type: text
|
||||
label: Navigation Title
|
||||
class: large
|
||||
maxlength: 60
|
||||
fieldsetcontent:
|
||||
type: fieldset
|
||||
legend: Meta-Content
|
||||
fields:
|
||||
title:
|
||||
type: text
|
||||
label: Meta title
|
||||
maxlength: 100
|
||||
class: large
|
||||
description:
|
||||
type: textarea
|
||||
label: Meta description
|
||||
size: 160
|
||||
class: large
|
||||
description: If not filled, the description is extracted from content.
|
||||
heroimage:
|
||||
type: image
|
||||
label: Hero Image
|
||||
description: Maximum size for an image is 5 MB. Hero images are not supported by all themes.
|
||||
heroimagealt:
|
||||
type: text
|
||||
label: Alternative Text for the hero image
|
||||
fieldsetvisibility:
|
||||
type: fieldset
|
||||
legend: Visibility
|
||||
fields:
|
||||
hide:
|
||||
type: checkbox
|
||||
label: Hide
|
||||
checkboxlabel: Hide page from navigation
|
||||
class: medium
|
||||
noindex:
|
||||
type: checkbox
|
||||
label: Noindex
|
||||
checkboxlabel: Add noindex tag and exclude from sitemap
|
||||
class: medium
|
||||
fieldsetauthor:
|
||||
type: fieldset
|
||||
legend: Author
|
||||
fields:
|
||||
owner:
|
||||
type: text
|
||||
label: owner (username)
|
||||
class: medium
|
||||
description: Has edit rights for this article.
|
||||
author:
|
||||
type: text
|
||||
label: author
|
||||
class: medium
|
||||
description: Can be used for author line in frontend.
|
||||
fieldsetrights:
|
||||
type: fieldset
|
||||
legend: Access & Rights
|
||||
fields:
|
||||
allowedrole:
|
||||
type: select
|
||||
label: For access the user must have this minimum role
|
||||
class: medium
|
||||
dataset: userroles
|
||||
options:
|
||||
description: Select the lowest userrole. Higher roles will have access too.
|
||||
alloweduser:
|
||||
type: text
|
||||
label: Only the following users have access
|
||||
class: medium
|
||||
description: Add one or more usernames separated with comma.
|
||||
fieldsetpubdate:
|
||||
type: fieldset
|
||||
legend: Article Date
|
||||
fields:
|
||||
manualdate:
|
||||
type: date
|
||||
label: Manual date
|
||||
modified:
|
||||
type: date
|
||||
label: Last modified live (readonly)
|
||||
readonly: readonly
|
||||
class: medium
|
||||
description: Used as fallback when no manual date is set.
|
||||
created:
|
||||
type: date
|
||||
label: Created at (read only)
|
||||
readonly: readonly
|
||||
class: medium
|
||||
time:
|
||||
type: text
|
||||
readonly: readonly
|
||||
hidden: true
|
||||
class: hidden
|
||||
pattern: '[0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
|
||||
contains:
|
||||
type: radio
|
||||
label: This folder contains
|
||||
class: medium
|
||||
options:
|
||||
pages: PAGES (sort in navigation with drag & drop)
|
||||
posts: POSTS (sorted by publish date, for news or blogs)
|
32
system/typemill/settings/permissions.yaml
Normal file
32
system/typemill/settings/permissions.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
member:
|
||||
name: member
|
||||
inherits: NULL
|
||||
permissions:
|
||||
user:
|
||||
- 'view'
|
||||
- 'update'
|
||||
- 'delete'
|
||||
author:
|
||||
name: author
|
||||
inherits: member
|
||||
permissions:
|
||||
mycontent:
|
||||
- 'view'
|
||||
- 'create'
|
||||
- 'update'
|
||||
content:
|
||||
- 'view'
|
||||
editor:
|
||||
name: editor
|
||||
inherits: author
|
||||
permissions:
|
||||
mycontent:
|
||||
- 'delete'
|
||||
- 'publish'
|
||||
- 'unpublish'
|
||||
content:
|
||||
- 'create'
|
||||
- 'update'
|
||||
- 'delete'
|
||||
- 'publish'
|
||||
- 'unpublish'
|
5
system/typemill/settings/resources.yaml
Normal file
5
system/typemill/settings/resources.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
- 'content'
|
||||
- 'mycontent'
|
||||
- 'user'
|
||||
- 'userlist'
|
||||
- 'system'
|
12
system/typemill/settings/system.yaml
Normal file
12
system/typemill/settings/system.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
basics:
|
||||
fields:
|
||||
media:
|
||||
fields:
|
||||
writing:
|
||||
fields:
|
||||
access:
|
||||
fields:
|
||||
password:
|
||||
fields:
|
||||
developer:
|
||||
fields:
|
@@ -1,82 +1,428 @@
|
||||
<?php
|
||||
|
||||
# included from /public/index.php
|
||||
|
||||
use DI\Container;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
#use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||
use Slim\Exception\HttpNotFoundException;
|
||||
use Slim\Middleware\ErrorMiddleware;
|
||||
use Slim\Psr7\Response as NewResponse;
|
||||
use Slim\Psr7\Response as Response;
|
||||
use Slim\Factory\AppFactory;
|
||||
use Slim\Views\Twig;
|
||||
use Slim\Views\TwigMiddleware;
|
||||
use Slim\Csrf\Guard;
|
||||
use Slim\Flash\Messages;
|
||||
use Nquire\Middleware\ValidationErrors;
|
||||
use Nquire\Middleware\FlashMessages;
|
||||
use Nquire\Middleware\JsonBodyParser;
|
||||
use Typemill\Events\OnSettingsLoaded;
|
||||
use Typemill\Events\OnPluginsLoaded;
|
||||
use Typemill\Events\OnSessionSegmentsLoaded;
|
||||
use Typemill\Events\OnRolesPermissionsLoaded;
|
||||
use Typemill\Events\OnResourcesLoaded;
|
||||
use Typemill\Middleware\JsonBodyParser;
|
||||
use Typemill\Middleware\CreateSession;
|
||||
use Typemill\Middleware\TwigView;
|
||||
use Typemill\Middleware\CsrfProtection;
|
||||
use Typemill\Middleware\CsrfProtectionToMiddleware;
|
||||
use Typemill\Middleware\FlashMessages;
|
||||
#use Typemill\Middleware\ValidationErrors;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$timer = [];
|
||||
$timer['start'] = microtime(true);
|
||||
|
||||
/****************************
|
||||
* HIDE ERRORS BY DEFAULT *
|
||||
* HIDE ERRORS BY DEFAULT *
|
||||
****************************/
|
||||
|
||||
ini_set('display_errors', 0);
|
||||
ini_set('display_startup_errors', 0);
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
|
||||
/****************************
|
||||
* CONTAINER *
|
||||
* LOAD SETTINGS *
|
||||
****************************/
|
||||
|
||||
$settings = Typemill\Static\Settings::loadSettings($rootpath);
|
||||
|
||||
|
||||
/****************************
|
||||
* HANDLE DISPLAY ERRORS *
|
||||
****************************/
|
||||
|
||||
if(isset($settings['displayErrorDetails']) && $settings['displayErrorDetails'])
|
||||
{
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
}
|
||||
|
||||
$timer['settings'] = microtime(true);
|
||||
|
||||
/****************************
|
||||
* CREATE CONTAINER *
|
||||
****************************/
|
||||
|
||||
# https://www.slimframework.com/docs/v4/start/upgrade.html#changes-to-container
|
||||
|
||||
$container = new Container();
|
||||
AppFactory::setContainer($container);
|
||||
|
||||
$app = AppFactory::create();
|
||||
$container = $app->getContainer();
|
||||
|
||||
$responseFactory = $app->getResponseFactory();
|
||||
$routeParser = $app->getRouteCollector()->getRouteParser();
|
||||
|
||||
# add route parser to conatiner to use named routes in controller
|
||||
$container->set('routeParser', $routeParser);
|
||||
|
||||
$timer['container'] = microtime(true);
|
||||
|
||||
/****************************
|
||||
* BASE PATH *
|
||||
* BASE URL AND ROOT PATH *
|
||||
****************************/
|
||||
|
||||
# basepath must always be set in slim 4
|
||||
$basepath = preg_replace('/(.*)\/.*/', '$1', $_SERVER['SCRIPT_NAME']);
|
||||
|
||||
$container->set('basePath', $basepath);
|
||||
$uriFactory = new \Slim\Psr7\Factory\UriFactory();
|
||||
$uri = $uriFactory->createFromGlobals($_SERVER);
|
||||
$uripath = $uri->getPath();
|
||||
$basepath = preg_replace('/(.*)\/.*/', '$1', $_SERVER['SCRIPT_NAME']);
|
||||
$routepath = str_replace($basepath, '', $uripath);
|
||||
|
||||
# in slim 4 you alsways have to set application basepath
|
||||
$app->setBasePath($basepath);
|
||||
|
||||
die('hello Typemill V2');
|
||||
$container->set('basePath', $basepath);
|
||||
$container->set('rootPath', $rootpath);
|
||||
$container->set('uriPath', $uripath);
|
||||
$container->set('routePath', $routepath);
|
||||
|
||||
|
||||
/****************************
|
||||
* SETTINGS *
|
||||
* CREATE EVENT DISPATCHER *
|
||||
****************************/
|
||||
$settings = require __DIR__ . '/settings/settings.php';
|
||||
|
||||
$container->set('settings', function() use ($settings)
|
||||
$dispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher();
|
||||
|
||||
|
||||
/****************************
|
||||
* LOAD & UPDATE PLUGINS *
|
||||
****************************/
|
||||
|
||||
$plugins = Typemill\Static\Plugins::loadPlugins($rootpath);
|
||||
$pluginSettings = $routes = $middleware = [];
|
||||
|
||||
# if there are less plugins in the scan than in the settings, then a plugin has been removed
|
||||
if(count($plugins) < count($settings['plugins']))
|
||||
{
|
||||
return $settings;
|
||||
});
|
||||
$updateSettings = true;
|
||||
}
|
||||
|
||||
|
||||
# create a session
|
||||
ini_set('session.cookie_httponly', 1 );
|
||||
ini_set('session.use_strict_mode', 1);
|
||||
ini_set('session.cookie_samesite', 'lax');
|
||||
if(isset($_SERVER['HTTPS']))
|
||||
foreach($plugins as $plugin)
|
||||
{
|
||||
ini_set('session.cookie_secure', 1);
|
||||
session_name('__Secure-nquire-session');
|
||||
$pluginName = $plugin['name'];
|
||||
$className = $plugin['className'];
|
||||
|
||||
# if plugin is not in the settings already
|
||||
if(!isset($settings['plugins'][$pluginName]))
|
||||
{
|
||||
# it is a new plugin. Add it and set active to false
|
||||
$settings['plugins'][$pluginName] = ['active' => false];
|
||||
|
||||
# and set flag to refresh the settings
|
||||
$updateSettings = true;
|
||||
}
|
||||
|
||||
# if the plugin is activated, add routes/middleware and add plugin as event subscriber
|
||||
if($settings['plugins'][$pluginName]['active'])
|
||||
{
|
||||
$routes = Typemill\Static\Plugins::getNewRoutes($className, $routes);
|
||||
$middleware = Typemill\Static\Plugins::getNewMiddleware($className, $middleware);
|
||||
|
||||
$dispatcher->addSubscriber(new $className($container));
|
||||
}
|
||||
}
|
||||
|
||||
# if plugins have been added or removed
|
||||
if(isset($updateSettings))
|
||||
{
|
||||
# update stored settings file
|
||||
Typemill\settings::updateSettings($settings);
|
||||
}
|
||||
|
||||
# add final settings to the container
|
||||
$container->set('settings', function() use ($settings){ return $settings; });
|
||||
|
||||
# dispatch the event onPluginsLoaded
|
||||
$dispatcher->dispatch(new OnPluginsLoaded($plugins), 'onPluginsLoaded');
|
||||
|
||||
# dispatch settings event and get all setting-updates from plugins
|
||||
$dispatcher->dispatch(new OnSettingsLoaded($settings), 'onSettingsLoaded')->getData();
|
||||
|
||||
$timer['plugins'] = microtime(true);
|
||||
|
||||
|
||||
/****************************
|
||||
* LOAD ROLES & PERMISSIONS *
|
||||
****************************/
|
||||
|
||||
# load roles and permissions
|
||||
$rolesAndPermissions = Typemill\Static\Permissions::loadRolesAndPermissions($settings['defaultSettingsPath']);
|
||||
|
||||
# dispatch roles so plugins can enhance them
|
||||
$rolesAndPermissions = $dispatcher->dispatch(new OnRolesPermissionsLoaded($rolesAndPermissions), 'onRolesPermissionsLoaded')->getData();
|
||||
|
||||
# load resources
|
||||
$resources = Typemill\Static\Permissions::loadResources($settings['defaultSettingsPath']);
|
||||
|
||||
# dispatch roles so plugins can enhance them
|
||||
$resources = $dispatcher->dispatch(new OnResourcesLoaded($resources), 'onResourcesLoaded')->getData();
|
||||
|
||||
# create acl-object
|
||||
$acl = Typemill\Static\Permissions::createAcl($rolesAndPermissions, $resources);
|
||||
|
||||
# add acl to container
|
||||
$container->set('acl', function() use ($acl){ return $acl; });
|
||||
|
||||
$timer['permissions'] = microtime(true);
|
||||
|
||||
|
||||
/****************************
|
||||
* SEGMENTS WITH SESSION *
|
||||
****************************/
|
||||
|
||||
# if website is restricted to registered user
|
||||
if( ( isset($settings['access']) && $settings['access'] ) || ( isset($settings['pageaccess']) && $settings['pageaccess'] ) )
|
||||
{
|
||||
# activate session for all routes
|
||||
$session_segments = [$routepath];
|
||||
}
|
||||
else
|
||||
{
|
||||
session_name('nquire-session');
|
||||
$session_segments = ['setup', 'tm/', 'api/'];
|
||||
|
||||
# let plugins add own segments for session, eg. to enable csrf for forms
|
||||
$client_segments = $dispatcher->dispatch(new OnSessionSegmentsLoaded([]), 'onSessionSegmentsLoaded')->getData();
|
||||
$session_segments = array_merge($session_segments, $client_segments);
|
||||
}
|
||||
session_start();
|
||||
|
||||
# start session
|
||||
# Typemill\Static\Session::startSessionForSegments($session_segments, $routepath);
|
||||
|
||||
$timer['session segments'] = microtime(true);
|
||||
|
||||
/****************************
|
||||
* OTHER CONTAINER ITEMS *
|
||||
****************************/
|
||||
|
||||
# Register Middleware On Container
|
||||
if(isset($_SESSION)){
|
||||
$container->set('csrf', function () use ($responseFactory){ return new Guard($responseFactory); });
|
||||
}
|
||||
|
||||
# dispatcher to container
|
||||
$container->set('dispatcher', function() use ($dispatcher){ return $dispatcher; });
|
||||
|
||||
# asset function for plugins
|
||||
$container->set('assets', function() use ($basepath){ return new \Typemill\Assets($basepath); });
|
||||
|
||||
$timer['other container'] = microtime(true);
|
||||
|
||||
|
||||
/****************************
|
||||
* MIDDLEWARE *
|
||||
****************************/
|
||||
|
||||
# Add Validation Errors Middleware
|
||||
# $app->add(new ValidationErrors($container->get('view')));
|
||||
|
||||
# Add Flash Messages Middleware
|
||||
# $app->add(new FlashMessages($container->get('view')));
|
||||
|
||||
# Add Twig-View Middleware
|
||||
# $app->add(TwigMiddleware::createFromContainer($app));
|
||||
|
||||
# if session add flash messages
|
||||
$app->add(new FlashMessages($container));
|
||||
|
||||
/*
|
||||
if(isset($_SESSION))
|
||||
{
|
||||
echo '<br>add csrf';
|
||||
# Register Middleware To Be Executed On All Routes
|
||||
$app->add('csrf');
|
||||
}
|
||||
*/
|
||||
|
||||
# $container->set('csrf', null);
|
||||
|
||||
# $app->add('csrf');
|
||||
# $app->add(new CsrfProtectionToMiddleware($container));
|
||||
|
||||
|
||||
$app->add(function($request, $handler) use ($container){
|
||||
$response = $handler->handle($request);
|
||||
$existingContent = (string) $response->getBody();
|
||||
|
||||
$response = new Response();
|
||||
$response->getBody()->write('BEFORE' . $existingContent);
|
||||
|
||||
return $response;
|
||||
});
|
||||
|
||||
# if session add csrf protection
|
||||
$app->add(new CsrfProtection($container, $responseFactory));
|
||||
|
||||
# add session
|
||||
$app->add(new CreateSession($session_segments, ltrim($routepath, '/') ));
|
||||
|
||||
# check if user : apikey
|
||||
# if yes
|
||||
# validate it as normal password
|
||||
# do not create sessions
|
||||
# set authentication to true somehow
|
||||
|
||||
# add JsonBodyParser Middleware
|
||||
$app->add(new JsonBodyParser());
|
||||
|
||||
# routing middleware earlier than error middleware so errors are shown
|
||||
$app->addRoutingMiddleware();
|
||||
|
||||
# error middleware
|
||||
$errorMiddleware = new ErrorMiddleware(
|
||||
$app->getCallableResolver(),
|
||||
$app->getResponseFactory(),
|
||||
true,
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
# Set the Not Found Handler
|
||||
$errorMiddleware->setErrorHandler(HttpNotFoundException::class, function ($request, $exception) use ($container) {
|
||||
|
||||
$response = new NewResponse();
|
||||
|
||||
return $container->get('view')->render($response->withStatus(404), '404.twig');
|
||||
|
||||
});
|
||||
|
||||
$app->add($errorMiddleware);
|
||||
|
||||
$timer['middleware'] = microtime(true);
|
||||
|
||||
/************************
|
||||
* ADD ROUTES *
|
||||
************************/
|
||||
|
||||
require __DIR__ . '/routes/api.php';
|
||||
require __DIR__ . '/routes/web.php';
|
||||
|
||||
$timer['routes'] = microtime(true);
|
||||
|
||||
/************************
|
||||
* RUN APP *
|
||||
************************/
|
||||
|
||||
$app->run();
|
||||
|
||||
$timer['run'] = microtime(true);
|
||||
|
||||
Typemill\Static\Helpers::printTimer($timer);
|
||||
|
||||
die('After app run');
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************
|
||||
* MOVE TO MIDDLEWARE NEXT TIME *
|
||||
********************************/
|
||||
|
||||
print_r($session_segments);
|
||||
|
||||
$trimmedRoute = ltrim($routepath,'/');
|
||||
|
||||
foreach($session_segments as $segment)
|
||||
{
|
||||
|
||||
$test = substr( $trimmedRoute, 0, strlen($segment) );
|
||||
|
||||
echo '<br>' . $test . ' = ' . $segment;
|
||||
continue;
|
||||
|
||||
if(substr( $uri->getPath(), 0, strlen($segment) ) === ltrim($segment, '/'))
|
||||
{
|
||||
// configure session
|
||||
ini_set('session.cookie_httponly', 1 );
|
||||
ini_set('session.use_strict_mode', 1);
|
||||
ini_set('session.cookie_samesite', 'lax');
|
||||
if($uri->getScheme() == 'https')
|
||||
{
|
||||
ini_set('session.cookie_secure', 1);
|
||||
session_name('__Secure-typemill-session');
|
||||
}
|
||||
else
|
||||
{
|
||||
session_name('typemill-session');
|
||||
}
|
||||
|
||||
// add csrf-protection
|
||||
$container['csrf'] = function ($c)
|
||||
{
|
||||
$guard = new \Slim\Csrf\Guard();
|
||||
$guard->setPersistentTokenMode(true);
|
||||
$guard->setfailurecallable(function ($request, $response, $next)
|
||||
{
|
||||
$request = $request->withattribute("csrf_result", false);
|
||||
return $next($request, $response);
|
||||
});
|
||||
|
||||
return $guard;
|
||||
};
|
||||
|
||||
// add flash to container
|
||||
$container['flash'] = function ()
|
||||
{
|
||||
return new \Slim\Flash\Messages();
|
||||
};
|
||||
|
||||
// start session
|
||||
session_start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Typemill\Static\Helpers::printTimer($timer);
|
||||
|
||||
die('Typemill 2 is comming');
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# add flash messsages
|
||||
$container->set('flash', function(){
|
||||
|
Reference in New Issue
Block a user