mirror of
https://github.com/typemill/typemill.git
synced 2025-07-31 11:20:15 +02:00
Add update checker and proxy detection
This commit is contained in:
@@ -127,6 +127,7 @@ abstract class Controller
|
||||
return $formDefinitions;
|
||||
}
|
||||
|
||||
# used to protect api access, can we do it with middleware?
|
||||
protected function validateRights($userrole, $resource, $action)
|
||||
{
|
||||
$acl = $this->c->get('acl');
|
||||
@@ -136,7 +137,9 @@ abstract class Controller
|
||||
return true;
|
||||
}
|
||||
|
||||
# check ownership.
|
||||
die("PLEASE UPDATE THE METHOD validateRights in controller.php");
|
||||
# check ownership. THIS WILL FAIL ANYWAY!!!
|
||||
# MAYBE WE SHOUD ADD THIS CHECK INTO MIDDLEWARE, TOO ?
|
||||
|
||||
$writeMeta = new writeMeta();
|
||||
$pagemeta = $writeMeta->getPageMeta($this->settings, $this->item);
|
||||
@@ -159,74 +162,4 @@ abstract class Controller
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
# move to another place??
|
||||
protected function recursiveValidation($validator, array $formdefinitions, $input, $output = [])
|
||||
{
|
||||
# loop through form-definitions, ignores everything that is not defined in yaml
|
||||
foreach($formdefinitions as $fieldname => $fielddefinitions)
|
||||
{
|
||||
if(is_array($fielddefinitions) && $fielddefinitions['type'] == 'fieldset')
|
||||
{
|
||||
$output = $this->recursiveValidation($validator, $fielddefinitions['fields'], $input, $output);
|
||||
}
|
||||
|
||||
# do not store values for disabled fields
|
||||
if(isset($fielddefinitions['disabled']) && $fielddefinitions['type'])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isset($input[$fieldname]))
|
||||
{
|
||||
$fieldvalue = $input[$fieldname];
|
||||
|
||||
# fix false or null values for selectboxes
|
||||
if($fielddefinitions['type'] == "select" && ($fieldvalue === 'NULL' OR $fieldvalue === false))
|
||||
{
|
||||
$fieldvalue = NULL;
|
||||
}
|
||||
|
||||
$validationresult = $validator->field($fieldname, $fieldvalue, $fielddefinitions);
|
||||
|
||||
if($validationresult === true)
|
||||
{
|
||||
# MOVE THIS TO A SEPARATE FUNCTION SO YOU CAN STORE IMAGES ONLY IF ALL FIELDS SUCCESSFULLY VALIDATED
|
||||
# images have special treatment, check ProcessImage-Model and ImageApiController
|
||||
if($fielddefinitions['type'] == 'image')
|
||||
{
|
||||
# then check if file is there already: check for name and maybe correct image extension (if quality has been changed)
|
||||
$storage = new StorageWrapper('\Typemill\Models\Storage');
|
||||
$existingImagePath = $storage->checkImage($fieldvalue);
|
||||
|
||||
if($existingImagePath)
|
||||
{
|
||||
$fieldvalue = $existingImagePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
# there is no published image with that name, so check if there is an unpublished image in tmp folder and publish it
|
||||
$newImagePath = $storage->publishImage($fieldvalue);
|
||||
if($newImagePath)
|
||||
{
|
||||
$fieldvalue = $newImagePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
$fieldvalue = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$output[$fieldname] = $fieldvalue;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->errors[$fieldname] = $validationresult[$fieldname][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
@@ -9,7 +9,14 @@ use Typemill\Models\StorageWrapper;
|
||||
use Typemill\Models\Validation;
|
||||
use Typemill\Models\Navigation;
|
||||
use Typemill\Models\Content;
|
||||
use Typemill\Models\Meta;
|
||||
use Typemill\Models\Sitemap;
|
||||
use Typemill\Static\Slug;
|
||||
use Typemill\Events\OnPagePublished;
|
||||
use Typemill\Events\OnPageUnpublished;
|
||||
use Typemill\Events\OnPageDeleted;
|
||||
use Typemill\Events\OnPageSorted;
|
||||
use Typemill\Events\OnPageRenamed;
|
||||
|
||||
class ControllerApiAuthorArticle extends Controller
|
||||
{
|
||||
@@ -70,25 +77,29 @@ class ControllerApiAuthorArticle extends Controller
|
||||
$draftNavigation = $navigation->setActiveNaviItems($draftNavigation, $item->keyPathArray);
|
||||
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
|
||||
|
||||
$sitemap = new Sitemap();
|
||||
$sitemap->updateSitemap($draftNavigation, $urlinfo);
|
||||
|
||||
# META is important e.g. for newsletter, so send it, too
|
||||
$meta = new Meta();
|
||||
$metadata = $meta->getMetaData($item);
|
||||
$metadata = $meta->addMetaDefaults($metadata, $item, $this->settings['author']);
|
||||
# $metadata = $meta->addMetaTitleDescription($metadata, $item, $markdownArray);
|
||||
|
||||
# dispatch event, e.g. send newsletter and more
|
||||
$data = [
|
||||
'markdown' => $draftMarkdown,
|
||||
'item' => $item,
|
||||
'meta' => $metadata
|
||||
];
|
||||
$this->c->get('dispatcher')->dispatch(new OnPagePublished($data), 'onPagePublished');
|
||||
|
||||
$response->getBody()->write(json_encode([
|
||||
'navigation' => $draftNavigation,
|
||||
'item' => $item
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json');
|
||||
|
||||
/*
|
||||
# update the sitemap
|
||||
$this->updateSitemap($ping = true);
|
||||
|
||||
# complete the page meta if title or description not set
|
||||
$writeMeta = new WriteMeta();
|
||||
$meta = $writeMeta->completePageMeta($this->content, $this->settings, $this->item);
|
||||
|
||||
# dispatch event
|
||||
$page = ['content' => $this->content, 'meta' => $meta, 'item' => $this->item];
|
||||
$page = $this->c->dispatcher->dispatch('onPagePublished', new OnPagePublished($page))->getData();
|
||||
*/
|
||||
}
|
||||
|
||||
public function unpublishArticle(Request $request, Response $response, $args)
|
||||
@@ -140,6 +151,9 @@ class ControllerApiAuthorArticle extends Controller
|
||||
$draftNavigation = $navigation->setActiveNaviItems($draftNavigation, $item->keyPathArray);
|
||||
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
|
||||
|
||||
$sitemap = new Sitemap();
|
||||
$sitemap->updateSitemap($draftNavigation, $urlinfo);
|
||||
|
||||
# check if it is a folder and if the folder has published pages.
|
||||
$message = false;
|
||||
if($item->elementType == 'folder' && isset($item->folderContent))
|
||||
@@ -153,6 +167,9 @@ class ControllerApiAuthorArticle extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
# dispatch event
|
||||
$this->c->get('dispatcher')->dispatch(new OnPageUnpublished($item), 'onPageUnpublished');
|
||||
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => $message,
|
||||
'navigation' => $draftNavigation,
|
||||
@@ -274,11 +291,28 @@ class ControllerApiAuthorArticle extends Controller
|
||||
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
|
||||
$draftNavigation = $navigation->setActiveNaviItems($draftNavigation, $item->keyPathArray);
|
||||
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
|
||||
|
||||
$sitemap = new Sitemap();
|
||||
$sitemap->updateSitemap($draftNavigation, $urlinfo);
|
||||
|
||||
# refresh content
|
||||
$draftMarkdown = $content->getDraftMarkdown($item);
|
||||
$draftMarkdownHtml = $content->addDraftHtml($draftMarkdown);
|
||||
|
||||
# META is important e.g. for newsletter, so send it, too
|
||||
$meta = new Meta();
|
||||
$metadata = $meta->getMetaData($item);
|
||||
$metadata = $meta->addMetaDefaults($metadata, $item, $this->settings['author']);
|
||||
# $metadata = $meta->addMetaTitleDescription($metadata, $item, $markdownArray);
|
||||
|
||||
# dispatch event, e.g. send newsletter and more
|
||||
$data = [
|
||||
'markdown' => $draftMarkdown,
|
||||
'item' => $item,
|
||||
'meta' => $metadata
|
||||
];
|
||||
$this->c->get('dispatcher')->dispatch(new OnPagePublished($data), 'onPagePublished');
|
||||
|
||||
$response->getBody()->write(json_encode([
|
||||
'item' => $item,
|
||||
'navigation' => $draftNavigation,
|
||||
@@ -670,16 +704,24 @@ class ControllerApiAuthorArticle extends Controller
|
||||
}
|
||||
|
||||
$navigation->renameItem($item, $params['slug']);
|
||||
|
||||
$navigation->clearNavigation();
|
||||
# $this->updateSitemap($ping = true);
|
||||
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
|
||||
|
||||
$sitemap = new Sitemap();
|
||||
$sitemap->updateSitemap($draftNavigation, $urlinfo);
|
||||
|
||||
# create the new url for redirects
|
||||
$newUrlRel = str_replace($item->slug, $params['slug'], $item->urlRelWoF);
|
||||
$url = $urlinfo['baseurl'] . '/tm/content/' . $this->settings['editor'] . $newUrlRel;
|
||||
|
||||
|
||||
$data = [
|
||||
'item' => $item,
|
||||
'newUrl' => $newUrlRel
|
||||
];
|
||||
$this->c->get('dispatcher')->dispatch(new OnPageRenamed($data), 'onPageRenamed');
|
||||
|
||||
$response->getBody()->write(json_encode([
|
||||
'navigation' => $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']),
|
||||
'navigation' => $draftNavigation,
|
||||
'message' => '',
|
||||
'url' => $url
|
||||
]));
|
||||
@@ -687,7 +729,6 @@ class ControllerApiAuthorArticle extends Controller
|
||||
return $response->withHeader('Content-Type', 'application/json');
|
||||
}
|
||||
|
||||
|
||||
public function sortArticle(Request $request, Response $response, $args)
|
||||
{
|
||||
$validRights = $this->validateRights($request->getAttribute('c_userrole'), 'content', 'update');
|
||||
@@ -757,9 +798,6 @@ class ControllerApiAuthorArticle extends Controller
|
||||
# if the item has been moved within the same folder
|
||||
if($params['parent_id_from'] == $params['parent_id_to'])
|
||||
{
|
||||
# no need to ping search engines
|
||||
$ping = false;
|
||||
|
||||
# get key of item
|
||||
$itemKey = end($itemKeyPath);
|
||||
reset($itemKeyPath);
|
||||
@@ -769,9 +807,6 @@ class ControllerApiAuthorArticle extends Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
# let us ping search engines
|
||||
$ping = true;
|
||||
|
||||
# an active file has been moved to another folder, so send new url with response
|
||||
if($params['active'] == 'active')
|
||||
{
|
||||
@@ -807,9 +842,15 @@ class ControllerApiAuthorArticle extends Controller
|
||||
|
||||
# refresh navigation and item
|
||||
$navigation->clearNavigation();
|
||||
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
|
||||
|
||||
$sitemap = new Sitemap();
|
||||
$sitemap->updateSitemap($draftNavigation, $urlinfo);
|
||||
|
||||
$this->c->get('dispatcher')->dispatch(new OnPageSorted($params), 'onPageSorted');
|
||||
|
||||
$response->getBody()->write(json_encode([
|
||||
'navigation' => $navigation->getDraftNavigation($urlinfo, $langattr),
|
||||
'navigation' => $draftNavigation,
|
||||
'message' => '',
|
||||
'url' => false
|
||||
]));
|
||||
@@ -880,6 +921,9 @@ class ControllerApiAuthorArticle extends Controller
|
||||
$navigation->clearNavigation();
|
||||
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
|
||||
|
||||
$sitemap = new Sitemap();
|
||||
$sitemap->updateSitemap($draftNavigation, $urlinfo);
|
||||
|
||||
# check if it is a subfile or subfolder and set the redirect-url to the parent item
|
||||
$url = $urlinfo['baseurl'] . '/tm/content/' . $this->settings['editor'];
|
||||
if(count($item->keyPathArray) > 1)
|
||||
@@ -895,6 +939,9 @@ class ControllerApiAuthorArticle extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
# dispatch event
|
||||
$this->c->get('dispatcher')->dispatch(new OnPageDeleted($item), 'onPageDeleted');
|
||||
|
||||
$response->getBody()->write(json_encode([
|
||||
'url' => $url
|
||||
]));
|
||||
|
@@ -8,11 +8,15 @@ use Slim\Routing\RouteContext;
|
||||
use Typemill\Models\Validation;
|
||||
use Typemill\Models\Navigation;
|
||||
use Typemill\Models\Meta;
|
||||
use Typemill\Events\OnMetaLoaded;
|
||||
|
||||
|
||||
class ControllerApiAuthorMeta extends Controller
|
||||
{
|
||||
public function getMeta(Request $request, Response $response, $args)
|
||||
{
|
||||
|
||||
# is it really needed? Check middleware if rights are validated there already
|
||||
$validRights = $this->validateRights($request->getAttribute('c_userrole'), 'content', 'update');
|
||||
if(!$validRights)
|
||||
{
|
||||
@@ -87,6 +91,9 @@ class ControllerApiAuthorMeta extends Controller
|
||||
# store the metascheme in cache for frontend
|
||||
# $writeMeta->updateYaml('cache', 'metatabs.yaml', $metascheme);
|
||||
|
||||
$metacleared = $this->c->get('dispatcher')->dispatch(new OnMetaLoaded($metacleared),'onMetaLoaded')->getData();
|
||||
|
||||
|
||||
$response->getBody()->write(json_encode([
|
||||
'metadata' => $metacleared,
|
||||
'metadefinitions' => $metadefinitions,
|
||||
@@ -162,7 +169,7 @@ class ControllerApiAuthorMeta extends Controller
|
||||
$tabdefinitions = $this->flattenTabFields($tabdefinitions['fields'], []);
|
||||
|
||||
# create validation object
|
||||
$errors = false;
|
||||
$errors = [];
|
||||
|
||||
# take the user input data and iterate over all fields and values
|
||||
foreach($params['data'] as $fieldname => $fieldvalue)
|
||||
@@ -187,7 +194,7 @@ class ControllerApiAuthorMeta extends Controller
|
||||
}
|
||||
|
||||
# return validation errors
|
||||
if($errors)
|
||||
if(!empty($errors))
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => 'Please correct the errors.',
|
||||
|
@@ -23,12 +23,12 @@ class ControllerApiSystemPlugins extends Controller
|
||||
|
||||
# validate input
|
||||
$validator = new Validation();
|
||||
$validatedOutput = $this->recursiveValidation($validator, $formdefinitions, $plugininput);
|
||||
if(!empty($this->errors))
|
||||
$validatedOutput = $validator->recursiveValidation($formdefinitions, $plugininput);
|
||||
if(!empty($validator->errors))
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => 'Please correct tbe errors in form.',
|
||||
'errors' => $this->errors
|
||||
'errors' => $validator->errors
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
|
||||
|
@@ -34,13 +34,13 @@ class ControllerApiSystemSettings extends Controller
|
||||
|
||||
# validate input
|
||||
$validator = new Validation();
|
||||
$validatedOutput = $this->recursiveValidation($validator, $formdefinitions, $settingsinput);
|
||||
$validatedOutput = $validator->recursiveValidation($formdefinitions, $settingsinput);
|
||||
|
||||
if(!empty($this->errors))
|
||||
if(!empty($valiator->errors))
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => 'Please correct errors in form.',
|
||||
'errors' => $this->errors
|
||||
'errors' => $validator->errors
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
|
||||
|
@@ -23,12 +23,12 @@ class ControllerApiSystemThemes extends Controller
|
||||
|
||||
# validate input
|
||||
$validator = new Validation();
|
||||
$validatedOutput = $this->recursiveValidation($validator, $formdefinitions, $themeinput);
|
||||
if(!empty($this->errors))
|
||||
$validatedOutput = $validator->recursiveValidation($formdefinitions, $themeinput);
|
||||
if(!empty($validator->errors))
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => 'Please correct tbe errors in form.',
|
||||
'errors' => $this->errors
|
||||
'errors' => $validator->errors
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
|
||||
|
@@ -158,12 +158,12 @@ class ControllerApiSystemUsers extends Controller
|
||||
$formdefinitions = $user->getUserFields($this->c->get('acl'), $request->getAttribute('c_userrole'));
|
||||
|
||||
|
||||
$validatedOutput = $this->recursiveValidation($validate, $formdefinitions, $userdata);
|
||||
if(!empty($this->errors))
|
||||
$validatedOutput = $validate->recursiveValidation($formdefinitions, $userdata);
|
||||
if(!empty($validate->errors))
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => 'Please correct tbe errors in form.',
|
||||
'errors' => $this->errors
|
||||
'errors' => $validate->errors
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
|
||||
@@ -254,12 +254,12 @@ class ControllerApiSystemUsers extends Controller
|
||||
$user = new User();
|
||||
$formdefinitions = $user->getUserFields($this->c->get('acl'), $userdata['userrole'],$inspectorrole = $request->getAttribute('c_userrole'));
|
||||
unset($formdefinitions['username']['readonly']);
|
||||
$validatedOutput = $this->recursiveValidation($validate, $formdefinitions, $userdata);
|
||||
if(!empty($this->errors))
|
||||
$validatedOutput = $validate->recursiveValidation($formdefinitions, $userdata);
|
||||
if(!empty($validate->errors))
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => 'Please correct tbe errors in form.',
|
||||
'errors' => $this->errors
|
||||
'errors' => $validate->errors
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
|
||||
|
94
system/typemill/Controllers/ControllerApiSystemVersions.php
Normal file
94
system/typemill/Controllers/ControllerApiSystemVersions.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Controllers;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Typemill\Models\Validation;
|
||||
|
||||
class ControllerApiSystemVersions extends Controller
|
||||
{
|
||||
public function checkVersions(Request $request, Response $response)
|
||||
{
|
||||
$params = $request->getParsedBody();
|
||||
|
||||
# validate input
|
||||
$validate = new Validation();
|
||||
$vresult = $validate->checkVersions($params);
|
||||
if($vresult !== true)
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => 'The version check failed because of invalid parameters.'
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
|
||||
}
|
||||
|
||||
$type = $params['type'];
|
||||
$data = $params['data'];
|
||||
$url = 'https://typemill.net/api/v1/checkversion';
|
||||
|
||||
if($type == 'plugins')
|
||||
{
|
||||
$pluginList = '';
|
||||
foreach($data as $name => $plugin)
|
||||
{
|
||||
$pluginList .= $name . ',';
|
||||
}
|
||||
|
||||
$url = 'https://plugins.typemill.net/api/v1/getplugins?plugins=' . urlencode($pluginList);
|
||||
}
|
||||
if($type == 'themes')
|
||||
{
|
||||
$themeList = '';
|
||||
foreach($data as $name => $theme)
|
||||
{
|
||||
$themeList .= $name . ',';
|
||||
}
|
||||
|
||||
$url = 'https://themes.typemill.net/api/v1/getthemes?themes=' . urlencode($themeList);
|
||||
}
|
||||
|
||||
$opts = array(
|
||||
'http'=>array(
|
||||
'method'=>"GET",
|
||||
'ignore_errors' => true,
|
||||
'timeout' => 5,
|
||||
'header'=>"Referer: http://typemill-version2.net"
|
||||
)
|
||||
);
|
||||
|
||||
$context = stream_context_create($opts);
|
||||
$versions = file_get_contents($url, false, $context);
|
||||
$versions = json_decode($versions, true);
|
||||
$updateVersions = [];
|
||||
|
||||
if($type == 'system')
|
||||
{
|
||||
$latestVersion = $versions['system']['typemill'] ?? false;
|
||||
$installedVersion = $data ?? false;
|
||||
if($latestVersion && $installedVersion && version_compare($latestVersion, $installedVersion) <= 0)
|
||||
{
|
||||
$updateVersions['system'] = $latestVersion;
|
||||
}
|
||||
}
|
||||
elseif(isset($versions[$type]))
|
||||
{
|
||||
foreach($versions[$type] as $name => $details)
|
||||
{
|
||||
$latestVersion = $details['version'] ?? false;
|
||||
$installedVersion = $data[$name] ?? false;
|
||||
if($latestVersion && $installedVersion && version_compare($latestVersion, $installedVersion) <= 0)
|
||||
{
|
||||
$updateVersions[$name] = $details;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response->getBody()->write(json_encode([
|
||||
$type => $updateVersions
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
|
||||
}
|
||||
}
|
@@ -7,6 +7,11 @@ use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Slim\Routing\RouteContext;
|
||||
use Typemill\Models\Navigation;
|
||||
use Typemill\Models\Content;
|
||||
use Typemill\Events\OnPagetreeLoaded;
|
||||
use Typemill\Events\OnItemLoaded;
|
||||
use Typemill\Events\OnMarkdownLoaded;
|
||||
use Typemill\Events\OnPageReady;
|
||||
|
||||
|
||||
class ControllerWebAuthor extends Controller
|
||||
{
|
||||
@@ -46,8 +51,10 @@ class ControllerWebAuthor extends Controller
|
||||
# $draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
|
||||
|
||||
$draftNavigation = $navigation->setActiveNaviItems($draftNavigation, $keyPathArray);
|
||||
$draftNavigation = $this->c->get('dispatcher')->dispatch(new OnPagetreeLoaded($draftNavigation), 'onPagetreeLoaded')->getData();
|
||||
|
||||
$item = $navigation->getItemWithKeyPath($draftNavigation, $keyPathArray);
|
||||
$item = $this->c->get('dispatcher')->dispatch(new OnItemLoaded($item), 'onItemLoaded')->getData();
|
||||
}
|
||||
|
||||
# $item->modified = ($item->published OR $item->drafted) ? filemtime($this->settings['contentFolder'] . $this->path) : false;
|
||||
@@ -57,9 +64,11 @@ class ControllerWebAuthor extends Controller
|
||||
$content = new Content($urlinfo['baseurl']);
|
||||
|
||||
$draftMarkdown = $content->getDraftMarkdown($item);
|
||||
$draftMarkdown = $this->c->get('dispatcher')->dispatch(new OnMarkdownLoaded($draftMarkdown), 'onMarkdownLoaded')->getData();
|
||||
|
||||
$draftMarkdownHtml = $content->addDraftHtml($draftMarkdown);
|
||||
|
||||
|
||||
return $this->c->get('view')->render($response, 'content/blox-editor.twig', [
|
||||
'settings' => $this->settings,
|
||||
'mainnavi' => $mainNavigation,
|
||||
@@ -110,10 +119,11 @@ class ControllerWebAuthor extends Controller
|
||||
|
||||
# extend : $request->getAttribute('c_userrole')
|
||||
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
|
||||
|
||||
$draftNavigation = $navigation->setActiveNaviItems($draftNavigation, $keyPathArray);
|
||||
$draftNavigation = $this->c->get('dispatcher')->dispatch(new OnPagetreeLoaded($draftNavigation), 'onPagetreeLoaded')->getData();
|
||||
|
||||
$item = $navigation->getItemWithKeyPath($draftNavigation, $keyPathArray);
|
||||
$item = $this->c->get('dispatcher')->dispatch(new OnItemLoaded($item), 'onItemLoaded')->getData();
|
||||
}
|
||||
|
||||
# $item->modified = ($item->published OR $item->drafted) ? filemtime($this->settings['contentFolder'] . $this->path) : false;
|
||||
@@ -123,6 +133,7 @@ class ControllerWebAuthor extends Controller
|
||||
$content = new Content($urlinfo['baseurl']);
|
||||
|
||||
$draftMarkdown = $content->getDraftMarkdown($item);
|
||||
$draftMarkdown = $this->c->get('dispatcher')->dispatch(new OnMarkdownLoaded($draftMarkdown), 'onMarkdownLoaded')->getData();
|
||||
|
||||
$draftMarkdownHtml = $content->addDraftHtml($draftMarkdown);
|
||||
|
||||
@@ -140,78 +151,5 @@ class ControllerWebAuthor extends Controller
|
||||
'content' => $draftMarkdownHtml,
|
||||
]
|
||||
]);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# get params from call
|
||||
# $this->uri = $request->getUri()->withUserInfo('');
|
||||
# $this->params = isset($args['params']) ? ['url' => $this->uri->getBasePath() . '/' . $args['params']] : ['url' => $this->uri->getBasePath()];
|
||||
|
||||
# set structure
|
||||
if(!$this->setStructureDraft()){ return $this->renderIntern404($response, array( 'navigation' => true, 'content' => $this->errors )); }
|
||||
|
||||
# set information for homepage
|
||||
$this->setHomepage($args);
|
||||
|
||||
# set item
|
||||
if(!$this->setItem()){ return $this->renderIntern404($response, array( 'navigation' => $this->structure, 'settings' => $this->settings, 'content' => $this->errors )); }
|
||||
|
||||
# we have to check ownership here to use it for permission-check in tempates
|
||||
$this->checkContentOwnership();
|
||||
|
||||
# get the breadcrumb (here we need it only to mark the actual item active in navigation)
|
||||
$breadcrumb = isset($this->item->keyPathArray) ? Folder::getBreadcrumb($this->structureDraft, $this->item->keyPathArray) : false;
|
||||
|
||||
# set the status for published and drafted
|
||||
$this->setPublishStatus();
|
||||
|
||||
# set path
|
||||
$this->setItemPath($this->item->fileType);
|
||||
|
||||
# add the modified date for the file
|
||||
$this->item->modified = ($this->item->published OR $this->item->drafted) ? filemtime($this->settings['contentFolder'] . $this->path) : false;
|
||||
|
||||
# read content from file
|
||||
if(!$this->setContent()){ return $this->renderIntern404($response, array( 'navigation' => $this->structure, 'settings' => $this->settings, 'content' => $this->errors )); }
|
||||
|
||||
$content = $this->content;
|
||||
$title = false;
|
||||
|
||||
# if content is an array, then it is a draft
|
||||
if(is_array($content))
|
||||
{
|
||||
# transform array to markdown
|
||||
$parsedown = new ParsedownExtension($this->uri->getBaseUrl());
|
||||
$content = $parsedown->arrayBlocksToMarkdown($content);
|
||||
}
|
||||
|
||||
# if there is content
|
||||
if($content != '')
|
||||
{
|
||||
# normalize linebreaks
|
||||
$content = str_replace(array("\r\n", "\r"), "\n", $content);
|
||||
$content = trim($content, "\n");
|
||||
|
||||
# and strip out title
|
||||
if($content[0] == '#')
|
||||
{
|
||||
$contentParts = explode("\n", $content, 2);
|
||||
$title = trim($contentParts[0], "# \t\n\r\0\x0B");
|
||||
$content = trim($contentParts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->renderIntern($response, 'editor/editor-raw.twig', array(
|
||||
'acl' => $this->c->acl,
|
||||
'mycontent' => $this->mycontent,
|
||||
'navigation' => $this->structureDraft,
|
||||
'homepage' => $this->homepage,
|
||||
'title' => $title,
|
||||
'content' => $content,
|
||||
'item' => $this->item,
|
||||
'settings' => $this->settings
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
@@ -11,7 +11,6 @@ use Typemill\Models\Meta;
|
||||
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;
|
||||
|
@@ -368,6 +368,14 @@ class ControllerWebSystem extends Controller
|
||||
$dispatcher = $this->c->get('dispatcher')
|
||||
);
|
||||
|
||||
$pluginDefinitions = false;
|
||||
$pluginname = strtolower(trim(str_replace('tm/', '', $urlinfo['route']), '/'));
|
||||
if($pluginname && $pluginname != '' && isset($this->settings['plugins'][$pluginname]))
|
||||
{
|
||||
$extension = new Extension();
|
||||
$pluginDefinitions = $extension->getPluginDefinition($pluginname);
|
||||
}
|
||||
|
||||
return $this->c->get('view')->render($response, 'layouts/layoutSystemBlank.twig', [
|
||||
'settings' => $this->settings,
|
||||
'mainnavi' => $mainNavigation,
|
||||
@@ -377,6 +385,8 @@ class ControllerWebSystem extends Controller
|
||||
'labels' => $this->c->get('translations'),
|
||||
'urlinfo' => $this->c->get('urlinfo'),
|
||||
'acl' => $this->c->get('acl'),
|
||||
'userroles' => $this->c->get('acl')->getRoles(),
|
||||
'plugin' => $pluginDefinitions
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
14
system/typemill/Events/OnPageRenamed.php
Normal file
14
system/typemill/Events/OnPageRenamed.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Events;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for breadcrumb.
|
||||
*/
|
||||
|
||||
class OnPageRenamed extends BaseEvent
|
||||
{
|
||||
|
||||
}
|
@@ -4,9 +4,6 @@ namespace Typemill\Models;
|
||||
|
||||
use Typemill\Models\StorageWrapper;
|
||||
|
||||
|
||||
############## REFACTOR, it is similar or part of navigation
|
||||
|
||||
class Sitemap
|
||||
{
|
||||
private $storage;
|
||||
@@ -16,53 +13,15 @@ class Sitemap
|
||||
$this->storage = new StorageWrapper('\Typemill\Models\Storage');
|
||||
}
|
||||
|
||||
# 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)
|
||||
public function updateSitemap($navigation, $urlinfo)
|
||||
{
|
||||
$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 = $this->addUrlSet($sitemap, $urlinfo['baseurl']);
|
||||
$sitemap .= $this->generateUrlSets($navigation);
|
||||
$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);
|
||||
}
|
||||
|
||||
$this->storage->writeFile('cacheFolder', '', 'sitemap.xml', $sitemap);
|
||||
}
|
||||
|
||||
public function generateUrlSets($navigation)
|
||||
@@ -71,22 +30,25 @@ class Sitemap
|
||||
|
||||
foreach($navigation as $item)
|
||||
{
|
||||
if($item->elementType == 'folder' && isset($item->noindex) && $item->noindex === true)
|
||||
if($item->status == "published" OR $item->status == "modified")
|
||||
{
|
||||
$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);
|
||||
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;
|
||||
|
@@ -2,11 +2,16 @@
|
||||
|
||||
namespace Typemill\Models;
|
||||
|
||||
use Typemill\Models\User;
|
||||
use Valitron\Validator;
|
||||
use Typemill\Models\User;
|
||||
use Typemill\Models\StorageWrapper;
|
||||
|
||||
class Validation
|
||||
{
|
||||
|
||||
# only used for recursive validation
|
||||
public $errors = [];
|
||||
|
||||
/**
|
||||
* Constructor with custom validation rules
|
||||
*
|
||||
@@ -186,6 +191,33 @@ class Validation
|
||||
|
||||
return true;
|
||||
}, 'format is not valid.');
|
||||
|
||||
Validator::addRule('version', function($field, $value, array $params, array $fields)
|
||||
{
|
||||
if( version_compare( $value, '0.0.1', '>=' ) >= 0 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, 'not a valid version format.');
|
||||
|
||||
Validator::addRule('version_array', function($field, $value, array $params, array $fields)
|
||||
{
|
||||
foreach($value as $name => $version)
|
||||
{
|
||||
if(!preg_match("/^[A-Za-z0-9_\- ]+$/", $name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( version_compare( $version, '0.0.1', '>=' ) <= 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}, 'not a valid version format.');
|
||||
}
|
||||
|
||||
# return valitron standard object
|
||||
@@ -315,6 +347,34 @@ class Validation
|
||||
return $v->errors();
|
||||
}
|
||||
|
||||
public function checkVersions(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
$v->rule('required', ['type', 'data']);
|
||||
$v->rule('in', 'type', ['plugins', 'themes', 'system']);
|
||||
|
||||
if(!$v->validate())
|
||||
{
|
||||
return $v->errors();
|
||||
}
|
||||
|
||||
if($params['type'] == 'plugins' OR $params['type'] == 'themes')
|
||||
{
|
||||
$v->rule('version_array', 'data');
|
||||
}
|
||||
else
|
||||
{
|
||||
$v->rule('version', 'data');
|
||||
}
|
||||
|
||||
if(!$v->validate())
|
||||
{
|
||||
return $v->errors();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function navigationSort(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
@@ -498,60 +558,6 @@ class Validation
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public function usernameBREAK($username)
|
||||
{
|
||||
$v = new Validator($username);
|
||||
$v->rule('alphaNum', 'username')->message("Only alpha-numeric characters allowed");
|
||||
$v->rule('lengthBetween', 'username', 3, 20)->message("Length between 3 - 20");
|
||||
|
||||
return $this->validationResult($v);
|
||||
}
|
||||
|
||||
/**
|
||||
* validation for changing the password
|
||||
*
|
||||
* @param array $params with form data.
|
||||
* @return obj $v the validation object passed to a result method.
|
||||
*/
|
||||
|
||||
public function newPasswordOldBREAK(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
$v->rule('required', ['password', 'newpassword']);
|
||||
$v->rule('lengthBetween', 'newpassword', 5, 20);
|
||||
$v->rule('checkPassword', 'password')->message("Password is wrong");
|
||||
|
||||
return $this->validationResult($v);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* validation for changing the password api case
|
||||
*
|
||||
* @param array $params with form data.
|
||||
* @return obj $v the validation object passed to a result method.
|
||||
*/
|
||||
|
||||
public function newPasswordBREAK(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
$v->rule('required', ['password', 'newpassword']);
|
||||
$v->rule('lengthBetween', 'newpassword', 5, 20);
|
||||
$v->rule('checkPassword', 'password')->message("Password is wrong");
|
||||
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return $v->errors();
|
||||
}
|
||||
|
||||
/**
|
||||
* validation for password recovery
|
||||
*
|
||||
@@ -569,41 +575,6 @@ class Validation
|
||||
return $this->validationResult($v);
|
||||
}
|
||||
|
||||
/**
|
||||
* validation for system settings
|
||||
*
|
||||
* @param array $params with form data.
|
||||
* @return obj $v the validation object passed to a result method.
|
||||
*/
|
||||
|
||||
public function settingsBREAK(array $params, array $copyright, array $formats, $name = false)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
|
||||
$v->rule('required', ['title', 'author', 'copyright', 'year', 'editor']);
|
||||
$v->rule('lengthBetween', 'title', 2, 50);
|
||||
$v->rule('lengthBetween', 'author', 2, 50);
|
||||
$v->rule('noHTML', 'title');
|
||||
# $v->rule('regex', 'title', '/^[\pL0-9_ \-]*$/u');
|
||||
$v->rule('regex', 'author', '/^[\pL_ \-]*$/u');
|
||||
$v->rule('integer', 'year');
|
||||
$v->rule('length', 'year', 4);
|
||||
$v->rule('length', 'langattr', 2);
|
||||
$v->rule('in', 'editor', ['raw', 'visual']);
|
||||
$v->rule('values_allowed', 'formats', $formats);
|
||||
$v->rule('in', 'copyright', $copyright);
|
||||
$v->rule('noHTML', 'restrictionnotice');
|
||||
$v->rule('lengthBetween', 'restrictionnotice', 2, 1000 );
|
||||
$v->rule('email', 'recoverfrom');
|
||||
$v->rule('noHTML', 'recoversubject');
|
||||
$v->rule('lengthBetween', 'recoversubject', 2, 80 );
|
||||
$v->rule('noHTML', 'recovermessage');
|
||||
$v->rule('lengthBetween', 'recovermessage', 2, 1000 );
|
||||
$v->rule('iplist', 'trustedproxies');
|
||||
|
||||
return $this->validationResult($v, $name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* validation for content editor
|
||||
@@ -762,6 +733,78 @@ class Validation
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
# validate a whole formdefinition with all values
|
||||
public function recursiveValidation(array $formdefinitions, $input, $output = [])
|
||||
{
|
||||
# loop through form-definitions, ignores everything that is not defined in yaml
|
||||
foreach($formdefinitions as $fieldname => $fielddefinitions)
|
||||
{
|
||||
if(is_array($fielddefinitions) && $fielddefinitions['type'] == 'fieldset')
|
||||
{
|
||||
$output = $this->recursiveValidation($fielddefinitions['fields'], $input, $output);
|
||||
}
|
||||
|
||||
# do not store values for disabled fields
|
||||
if(isset($fielddefinitions['disabled']) && $fielddefinitions['type'])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isset($input[$fieldname]))
|
||||
{
|
||||
$fieldvalue = $input[$fieldname];
|
||||
|
||||
# fix false or null values for selectboxes
|
||||
if($fielddefinitions['type'] == "select" && ($fieldvalue === 'NULL' OR $fieldvalue === false))
|
||||
{
|
||||
$fieldvalue = NULL;
|
||||
}
|
||||
|
||||
$validationresult = $this->field($fieldname, $fieldvalue, $fielddefinitions);
|
||||
|
||||
if($validationresult === true)
|
||||
{
|
||||
# MOVE THIS TO A SEPARATE FUNCTION SO YOU CAN STORE IMAGES ONLY IF ALL FIELDS SUCCESSFULLY VALIDATED
|
||||
# images have special treatment, check ProcessImage-Model and ImageApiController
|
||||
if($fielddefinitions['type'] == 'image')
|
||||
{
|
||||
# then check if file is there already: check for name and maybe correct image extension (if quality has been changed)
|
||||
$storage = new StorageWrapper('\Typemill\Models\Storage');
|
||||
$existingImagePath = $storage->checkImage($fieldvalue);
|
||||
|
||||
if($existingImagePath)
|
||||
{
|
||||
$fieldvalue = $existingImagePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
# there is no published image with that name, so check if there is an unpublished image in tmp folder and publish it
|
||||
$newImagePath = $storage->publishImage($fieldvalue);
|
||||
if($newImagePath)
|
||||
{
|
||||
$fieldvalue = $newImagePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
$fieldvalue = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$output[$fieldname] = $fieldvalue;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->errors[$fieldname] = $validationresult[$fieldname][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* result for validation
|
||||
*
|
||||
@@ -771,6 +814,8 @@ class Validation
|
||||
|
||||
public function checkArray($arrayvalues, $v)
|
||||
{
|
||||
die('I think checkArray not in use anymore');
|
||||
|
||||
foreach($arrayvalues as $key => $value)
|
||||
{
|
||||
if(is_array($value))
|
||||
@@ -785,6 +830,8 @@ class Validation
|
||||
|
||||
public function validationResult($v, $name = false)
|
||||
{
|
||||
die("do not use validationResults in validation model anymore");
|
||||
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
|
@@ -3,8 +3,10 @@
|
||||
namespace Typemill;
|
||||
|
||||
use \Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use DI\Container;
|
||||
# use Typemill\Models\Fields;
|
||||
# use Typemill\Models\WriteYaml;
|
||||
use Typemill\Models\StorageWrapper;
|
||||
use Typemill\Models\Extension;
|
||||
use Typemill\Models\Validation;
|
||||
use Typemill\Extensions\ParsedownExtension;
|
||||
|
||||
@@ -18,9 +20,13 @@ abstract class Plugin implements EventSubscriberInterface
|
||||
|
||||
protected $editorroute = false;
|
||||
|
||||
|
||||
public function __construct($container)
|
||||
public function __construct(Container $container)
|
||||
{
|
||||
/*
|
||||
echo '<pre>';
|
||||
echo '<h1>FIRST</h1>';
|
||||
print_r($container);
|
||||
*/
|
||||
$this->container = $container;
|
||||
$this->urlinfo = $this->container->get('urlinfo');
|
||||
$this->route = $this->urlinfo['route'];
|
||||
@@ -42,9 +48,110 @@ abstract class Plugin implements EventSubscriberInterface
|
||||
return $this->container->get('settings');
|
||||
}
|
||||
|
||||
protected function getPluginSettings($plugin)
|
||||
protected function getPluginSettings($pluginname = false)
|
||||
{
|
||||
return $this->container->get('settings')['plugins'][$plugin];
|
||||
# $pluginClass = debug_backtrace(!DEBUG_BACKTRACE_PROVIDE_OBJECT|DEBUG_BACKTRACE_IGNORE_ARGS,2)[1]['class'];
|
||||
|
||||
$pluginname = $this->getPluginName($pluginname);
|
||||
|
||||
if($pluginname && isset($this->container->get('settings')['plugins'][$pluginname]))
|
||||
{
|
||||
return $this->container->get('settings')['plugins'][$pluginname];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function getPluginData($filename, $pluginname = false)
|
||||
{
|
||||
$pluginname = $this->getPluginName($pluginname);
|
||||
|
||||
$storageClass = $this->container->get('settings')['storage'];
|
||||
$storage = new StorageWrapper($storageClass);
|
||||
|
||||
$data = $storage->getFile('dataFolder', $pluginname, $filename);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getPluginYamlData($filename, $pluginname = false)
|
||||
{
|
||||
$pluginname = $this->getPluginName($pluginname);
|
||||
|
||||
$storageClass = $this->container->get('settings')['storage'];
|
||||
$storage = new StorageWrapper($storageClass);
|
||||
|
||||
$data = $storage->getYaml('dataFolder', $pluginname, $filename);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function storePluginData($filename, $pluginname = false)
|
||||
{
|
||||
$pluginname = $this->getPluginName($pluginname);
|
||||
|
||||
$storageClass = $this->container->get('settings')['storage'];
|
||||
$storage = new StorageWrapper($storageClass);
|
||||
|
||||
$result = $storage->writeFile('dataFolder', $pluginname, $filename);
|
||||
|
||||
if($result)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return $storage->getError();
|
||||
}
|
||||
|
||||
protected function storePluginYamlData(string $filename, array $data, $pluginname = false)
|
||||
{
|
||||
$pluginname = $this->getPluginName($pluginname);
|
||||
|
||||
# validation
|
||||
$extension = new Extension();
|
||||
$pluginDefinitions = $extension->getPluginDefinition($pluginname);
|
||||
$formDefinitions = $pluginDefinitions['system']['fields'] ?? false;
|
||||
|
||||
if($formDefinitions)
|
||||
{
|
||||
# where can we add this method so we can use it everywhere?
|
||||
# $formdefinitions = $this->addDatasets($formdefinitions);
|
||||
|
||||
$validate = new Validation();
|
||||
|
||||
$validatedOutput = $validate->recursiveValidation($formDefinitions, $data);
|
||||
if(!empty($validate->errors))
|
||||
{
|
||||
return $validate->errors;
|
||||
}
|
||||
}
|
||||
|
||||
$storageClass = $this->container->get('settings')['storage'];
|
||||
$storage = new StorageWrapper($storageClass);
|
||||
|
||||
$result = $storage->updateYaml('dataFolder', $pluginname, $filename, $data);
|
||||
|
||||
if($result)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return $storage->getError();
|
||||
}
|
||||
|
||||
private function getPluginName($pluginname)
|
||||
{
|
||||
if(!$pluginname)
|
||||
{
|
||||
$classname = get_called_class();
|
||||
|
||||
if ($pos = strrpos($classname, '\\'))
|
||||
{
|
||||
$pluginname = strtolower(substr($classname, $pos + 1));
|
||||
}
|
||||
}
|
||||
|
||||
return $pluginname;
|
||||
}
|
||||
|
||||
protected function urlinfo()
|
||||
@@ -84,11 +191,23 @@ abstract class Plugin implements EventSubscriberInterface
|
||||
$this->container->get('assets')->addJS($JS);
|
||||
}
|
||||
|
||||
/*
|
||||
protected function addEditorJS($JS)
|
||||
{
|
||||
$this->container->get('assets')->addEditorJS($JS);
|
||||
}
|
||||
|
||||
protected function addEditorInlineJS($JS)
|
||||
{
|
||||
$this->container->get('assets')->addEditorInlineJS($JS);
|
||||
}
|
||||
|
||||
protected function addEditorCSS($CSS)
|
||||
{
|
||||
$this->container->get('assets')->addEditorCSS($CSS);
|
||||
}
|
||||
*/
|
||||
|
||||
protected function addInlineJS($JS)
|
||||
{
|
||||
$this->container->get('assets')->addInlineJS($JS);
|
||||
@@ -98,11 +217,6 @@ abstract class Plugin implements EventSubscriberInterface
|
||||
{
|
||||
$this->container->get('assets')->addSvgSymbol($symbol);
|
||||
}
|
||||
|
||||
protected function addEditorInlineJS($JS)
|
||||
{
|
||||
$this->container->get('assets')->addEditorInlineJS($JS);
|
||||
}
|
||||
|
||||
protected function addCSS($CSS)
|
||||
{
|
||||
@@ -114,11 +228,6 @@ abstract class Plugin implements EventSubscriberInterface
|
||||
$this->container->get('assets')->addInlineCSS($CSS);
|
||||
}
|
||||
|
||||
protected function addEditorCSS($CSS)
|
||||
{
|
||||
$this->container->get('assets')->addEditorCSS($CSS);
|
||||
}
|
||||
|
||||
protected function getMeta()
|
||||
{
|
||||
return $this->container->get('assets')->meta;
|
||||
|
@@ -54,7 +54,7 @@ class Plugins
|
||||
$pluginRoute['route'] = strtolower($pluginRoute['route']);
|
||||
$routes[$routeType][] = $pluginRoute;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $routes;
|
||||
|
@@ -3,6 +3,7 @@ const app = Vue.createApp({
|
||||
<div class="w-full">
|
||||
<ul>
|
||||
<li v-for="(plugin,pluginname) in formDefinitions" class="w-full my-4 bg-stone-100">
|
||||
<p v-if="versions[pluginname] !== undefined"><a href="https://plugins.typemill.net" class="block p-2 text-center bg-rose-500 text-white">Please update to version {{ versions[pluginname].version }}</a></p>
|
||||
<div class="flex justify-between w-full px-8 py-3 border-b border-white" :class="getActiveClass(pluginname)">
|
||||
<p class="py-2">License: {{ plugin.license }}</p>
|
||||
<div class="flex">
|
||||
@@ -90,12 +91,43 @@ const app = Vue.createApp({
|
||||
userroles: false,
|
||||
showModal: false,
|
||||
modalMessage: 'default',
|
||||
versions: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
eventBus.$on('forminput', formdata => {
|
||||
this.formData[this.current][formdata.name] = formdata.value;
|
||||
});
|
||||
|
||||
var self = this;
|
||||
|
||||
var plugins = {};
|
||||
for (var key in this.formDefinitions)
|
||||
{
|
||||
if (this.formDefinitions.hasOwnProperty(key))
|
||||
{
|
||||
plugins[key] = this.formDefinitions[key].version;
|
||||
}
|
||||
}
|
||||
|
||||
tmaxios.post('/api/v1/versioncheck',{
|
||||
'url': data.urlinfo.route,
|
||||
'type': 'plugins',
|
||||
'data': plugins
|
||||
})
|
||||
.then(function (response)
|
||||
{
|
||||
if(response.data.plugins)
|
||||
{
|
||||
self.versions = response.data.plugins;
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
self.messageClass = 'bg-rose-500';
|
||||
self.message = error.response.data.message;
|
||||
});
|
||||
|
||||
},
|
||||
methods: {
|
||||
getActiveClass: function(pluginname)
|
||||
|
@@ -49,4 +49,5 @@ const translatefilter = {
|
||||
return data.labels[translation_key]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
const app = Vue.createApp({
|
||||
template: `<Transition name="initial" appear>
|
||||
<form class="inline-block w-full">
|
||||
<p v-if="version.system !== undefined"><a href="https://typemill.net" class="block p-2 text-center bg-rose-500 text-white">Please update typemill to version {{ version.system }}</a></p>
|
||||
<ul class="flex mt-4 mb-4">
|
||||
<li v-for="tab in tabs" class="">
|
||||
<button class="px-2 py-2 border-b-2 border-stone-200 hover:border-stone-700 transition duration-100" :class="(tab == currentTab) ? 'border-stone-700' : ''" @click.prevent="activateTab(tab)">{{ $filters.translate(tab) }}</button>
|
||||
@@ -34,10 +35,15 @@ const app = Vue.createApp({
|
||||
message: '',
|
||||
messageClass: '',
|
||||
errors: {},
|
||||
version: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
eventBus.$on('forminput', formdata => {
|
||||
this.formData[formdata.name] = formdata.value;
|
||||
});
|
||||
|
||||
for (var key in this.formDefinitions)
|
||||
{
|
||||
if (this.formDefinitions.hasOwnProperty(key))
|
||||
@@ -47,10 +53,26 @@ const app = Vue.createApp({
|
||||
}
|
||||
}
|
||||
|
||||
eventBus.$on('forminput', formdata => {
|
||||
this.formData[formdata.name] = formdata.value;
|
||||
});
|
||||
var self = this;
|
||||
|
||||
tmaxios.post('/api/v1/versioncheck',{
|
||||
'url': data.urlinfo.route,
|
||||
'type': 'system',
|
||||
'data': this.formData.version
|
||||
})
|
||||
.then(function (response)
|
||||
{
|
||||
if(response.data.system)
|
||||
{
|
||||
self.version = response.data.system;
|
||||
console.info(self.version);
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
self.messageClass = 'bg-rose-500';
|
||||
self.message = error.response.data.message;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
selectComponent: function(type)
|
||||
|
@@ -3,6 +3,7 @@ const app = Vue.createApp({
|
||||
<div class="w-full">
|
||||
<ul>
|
||||
<li v-for="(theme,themename) in formDefinitions" class="w-full my-4 bg-stone-100">
|
||||
<p v-if="versions[themename] !== undefined"><a href="https://themes.typemill.net" class="block p-2 text-center bg-rose-500 text-white">Please update to version {{ versions[themename].version }}</a></p>
|
||||
<div class="flex justify-between w-full px-8 py-3 border-b border-white" :class="getActiveClass(themename)">
|
||||
<p class="py-2">License: {{ theme.license }}</p>
|
||||
<div class="flex">
|
||||
@@ -93,6 +94,7 @@ const app = Vue.createApp({
|
||||
message: '',
|
||||
messageClass: '',
|
||||
errors: {},
|
||||
versions: false,
|
||||
userroles: false,
|
||||
showModal: false,
|
||||
modalMessage: 'default',
|
||||
@@ -104,6 +106,35 @@ const app = Vue.createApp({
|
||||
});
|
||||
this.deactivateThemes();
|
||||
this.formData[this.theme].active = true;
|
||||
|
||||
var self = this;
|
||||
|
||||
var themes = {};
|
||||
for (var key in this.formDefinitions)
|
||||
{
|
||||
if (this.formDefinitions.hasOwnProperty(key))
|
||||
{
|
||||
themes[key] = this.formDefinitions[key].version;
|
||||
}
|
||||
}
|
||||
|
||||
tmaxios.post('/api/v1/versioncheck',{
|
||||
'url': data.urlinfo.route,
|
||||
'type': 'themes',
|
||||
'data': themes
|
||||
})
|
||||
.then(function (response)
|
||||
{
|
||||
if(response.data.themes)
|
||||
{
|
||||
self.versions = response.data.themes;
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
self.messageClass = 'bg-rose-500';
|
||||
self.message = error.response.data.message;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
deactivateThemes: function()
|
||||
|
@@ -39,8 +39,6 @@
|
||||
</aside>
|
||||
|
||||
<article class="w-3/4 bg-stone-50 shadow-md p-8">
|
||||
|
||||
<h1 class="text-3xl font-bold mb-4">{{ translate('System') }} </h1>
|
||||
|
||||
<div id="system" v-cloak></div>
|
||||
|
||||
@@ -64,12 +62,13 @@
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/vue-eventbus.js?v={{ settings.version }}"></script>
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/vue-shared.js?v={{ settings.version }}"></script>
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/vue-medialib.js?v={{ settings.version }}"></script>
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/vue-forms.js?v={{ settings.version }}"></script>
|
||||
|
||||
{% block javascript %}{% endblock %}
|
||||
|
||||
{{ assets.renderJS() }}
|
||||
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/vue-forms.js?v={{ settings.version }}"></script>
|
||||
|
||||
<script>
|
||||
app.config.globalProperties.$filters = translatefilter;
|
||||
app.mount('#system');
|
||||
|
@@ -11,6 +11,7 @@ use Typemill\Controllers\ControllerApiSystemPlugins;
|
||||
use Typemill\Controllers\ControllerApiSystemExtensions;
|
||||
use Typemill\Controllers\ControllerApiSystemLicense;
|
||||
use Typemill\Controllers\ControllerApiSystemUsers;
|
||||
use Typemill\Controllers\ControllerApiSystemVersions;
|
||||
use Typemill\Controllers\ControllerApiImage;
|
||||
use Typemill\Controllers\ControllerApiFile;
|
||||
use Typemill\Controllers\ControllerApiAuthorArticle;
|
||||
@@ -31,6 +32,7 @@ $app->group('/api/v1', function (RouteCollectorProxy $group) use ($acl) {
|
||||
$group->post('/theme', ControllerApiSystemThemes::class . ':updateTheme')->setName('api.theme.set')->add(new ApiAuthorization($acl, 'system', 'update')); # admin
|
||||
$group->post('/plugin', ControllerApiSystemPlugins::class . ':updatePlugin')->setName('api.plugin.set')->add(new ApiAuthorization($acl, 'system', 'update')); # admin
|
||||
$group->post('/extensions', ControllerApiSystemExtensions::class . ':activateExtension')->setName('api.extension.activate')->add(new ApiAuthorization($acl, 'system', 'update')); # admin
|
||||
$group->post('/versioncheck', ControllerApiSystemVersions::class . ':checkVersions')->setName('api.versioncheck')->add(new ApiAuthorization($acl, 'system', 'update')); # admin
|
||||
$group->get('/users/getbynames', ControllerApiSystemUsers::class . ':getUsersByNames')->setName('api.usersbynames')->add(new ApiAuthorization($acl, 'user', 'update')); # admin
|
||||
$group->get('/users/getbyemail', ControllerApiSystemUsers::class . ':getUsersByEmail')->setName('api.usersbyemail')->add(new ApiAuthorization($acl, 'user', 'update')); # admin
|
||||
$group->get('/users/getbyrole', ControllerApiSystemUsers::class . ':getUsersByRole')->setName('api.usersbyrole')->add(new ApiAuthorization($acl, 'user', 'update')); # admin
|
||||
@@ -85,23 +87,26 @@ $app->group('/api/v1', function (RouteCollectorProxy $group) use ($acl) {
|
||||
})->add(new ApiAuthentication());
|
||||
|
||||
# api-routes from plugins
|
||||
foreach($routes['api'] as $pluginRoute)
|
||||
{
|
||||
$method = $pluginRoute['httpMethod'] ?? false;
|
||||
$route = $pluginRoute['route'] ?? false;
|
||||
$class = $pluginRoute['class'] ?? false;
|
||||
$name = $pluginRoute['name'] ?? false;
|
||||
$resource = $pluginRoute['resource'] ?? false;
|
||||
$privilege = $pluginRoute['privilege'] ?? false;
|
||||
if(isset($routes['api']) && !empty($routes['api']))
|
||||
{
|
||||
foreach($routes['api'] as $pluginRoute)
|
||||
{
|
||||
$method = $pluginRoute['httpMethod'] ?? false;
|
||||
$route = $pluginRoute['route'] ?? false;
|
||||
$class = $pluginRoute['class'] ?? false;
|
||||
$name = $pluginRoute['name'] ?? false;
|
||||
$resource = $pluginRoute['resource'] ?? false;
|
||||
$privilege = $pluginRoute['privilege'] ?? false;
|
||||
|
||||
if($resources && $privilege)
|
||||
{
|
||||
# protected api requires authentication and authorization
|
||||
$app->{$method}($route, $class)->setName($name)->add(new ApiAuthorization($acl, $resource, $privilege))->add(new ApiAuthentication());
|
||||
if($resources && $privilege)
|
||||
{
|
||||
# protected api requires authentication and authorization
|
||||
$app->{$method}($route, $class)->setName($name)->add(new ApiAuthorization($acl, $resource, $privilege))->add(new ApiAuthentication());
|
||||
}
|
||||
else
|
||||
{
|
||||
# public api routes
|
||||
$app->{$method}($route, $class)->setName($name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# public api routes
|
||||
$app->{$method}($route, $class)->setName($name);
|
||||
}
|
||||
}
|
||||
}
|
@@ -55,22 +55,25 @@ $app->redirect('/tm/', $routeParser->urlFor('auth.show'), 302);
|
||||
$app->get('/media/files[/{params:.*}]', ControllerWebDownload::class . ':download')->setName('download.file');
|
||||
|
||||
# web-routes from plugins
|
||||
foreach($routes['web'] as $pluginRoute)
|
||||
{
|
||||
$method = $pluginRoute['httpMethod'] ?? false;
|
||||
$route = $pluginRoute['route'] ?? false;
|
||||
$class = $pluginRoute['class'] ?? false;
|
||||
$name = $pluginRoute['name'] ?? false;
|
||||
$resource = $pluginRoute['resource'] ?? false;
|
||||
$privilege = $pluginRoute['privilege'] ?? false;
|
||||
if(isset($routes['web']) && !empty($routes['web']))
|
||||
{
|
||||
foreach($routes['web'] as $pluginRoute)
|
||||
{
|
||||
$method = $pluginRoute['httpMethod'] ?? false;
|
||||
$route = $pluginRoute['route'] ?? false;
|
||||
$class = $pluginRoute['class'] ?? false;
|
||||
$name = $pluginRoute['name'] ?? false;
|
||||
$resource = $pluginRoute['resource'] ?? false;
|
||||
$privilege = $pluginRoute['privilege'] ?? false;
|
||||
|
||||
if($resources && $privilege)
|
||||
{
|
||||
$app->{$method}($route, $class)->setName($name)->add(new WebAuthorization($routeParser, $acl, $resource, $privilege))->add(new WebRedirectIfUnauthenticated($routeParser));
|
||||
}
|
||||
else
|
||||
{
|
||||
$app->{$method}($route, $class)->setName($name);
|
||||
if($resources && $privilege)
|
||||
{
|
||||
$app->{$method}($route, $class)->setName($name)->add(new WebAuthorization($routeParser, $acl, $resource, $privilege))->add(new WebRedirectIfUnauthenticated($routeParser));
|
||||
}
|
||||
else
|
||||
{
|
||||
$app->{$method}($route, $class)->setName($name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,7 @@ use Slim\Views\TwigMiddleware;
|
||||
use Slim\Psr7\Factory\UriFactory;
|
||||
use Twig\Extension\DebugExtension;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use RKA\Middleware\ProxyDetection;
|
||||
use Typemill\Assets;
|
||||
use Typemill\Models\Settings;
|
||||
use Typemill\Models\License;
|
||||
@@ -358,8 +359,16 @@ $app->add($errorMiddleware);
|
||||
|
||||
$app->add(new SessionMiddleware($session_segments, $urlinfo['route']));
|
||||
|
||||
if(isset($settings['proxy']) && $settings['proxy'])
|
||||
{
|
||||
$trustedProxies = ( isset($settings['trustedproxies']) && !empty($settings['trustedproxies']) ) ? explode(",", $settings['trustedproxies']) : [];
|
||||
$app->add(new ProxyDetection($trustedProxies));
|
||||
}
|
||||
|
||||
|
||||
$timer['middleware'] = microtime(true);
|
||||
|
||||
|
||||
/************************
|
||||
* ADD ROUTES *
|
||||
************************/
|
||||
|
Reference in New Issue
Block a user