Merge branch 'feature138' into develop
This commit is contained in:
commit
296b5ac9da
41 changed files with 1356 additions and 520 deletions
|
@ -19,7 +19,8 @@
|
|||
"erusev/parsedown": "~1.4",
|
||||
"erusev/parsedown-extra": "dev-master",
|
||||
"jbroadway/urlify": "1.1.3",
|
||||
"vlucas/valitron": "dev-master"
|
||||
"vlucas/valitron": "dev-master",
|
||||
"laminas/laminas-permissions-acl": "^2.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
107
composer.lock
generated
107
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "b2dd4b8a1c943c5e407add9f1b9104ea",
|
||||
"content-hash": "87094a87b3a795ce73c299e4535358fb",
|
||||
"packages": [
|
||||
{
|
||||
"name": "erusev/parsedown",
|
||||
|
@ -159,6 +159,111 @@
|
|||
],
|
||||
"time": "2019-06-13T18:30:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laminas/laminas-permissions-acl",
|
||||
"version": "2.7.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laminas/laminas-permissions-acl.git",
|
||||
"reference": "624567fe376a70e0bfb5aa8217d5afa13b9d6e61"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-permissions-acl/zipball/624567fe376a70e0bfb5aa8217d5afa13b9d6e61",
|
||||
"reference": "624567fe376a70e0bfb5aa8217d5afa13b9d6e61",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"laminas/laminas-zendframework-bridge": "^1.0",
|
||||
"php": "^5.6 || ^7.0"
|
||||
},
|
||||
"replace": {
|
||||
"zendframework/zend-permissions-acl": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"laminas/laminas-coding-standard": "~1.0.0",
|
||||
"laminas/laminas-servicemanager": "^2.7.5 || ^3.0.3",
|
||||
"phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.5"
|
||||
},
|
||||
"suggest": {
|
||||
"laminas/laminas-servicemanager": "To support Laminas\\Permissions\\Acl\\Assertion\\AssertionManager plugin manager usage"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7.x-dev",
|
||||
"dev-develop": "2.8.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laminas\\Permissions\\Acl\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"description": "Provides a lightweight and flexible access control list (ACL) implementation for privileges management",
|
||||
"homepage": "https://laminas.dev",
|
||||
"keywords": [
|
||||
"acl",
|
||||
"laminas"
|
||||
],
|
||||
"time": "2019-12-31T17:37:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laminas/laminas-zendframework-bridge",
|
||||
"version": "1.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laminas/laminas-zendframework-bridge.git",
|
||||
"reference": "fcd87520e4943d968557803919523772475e8ea3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/fcd87520e4943d968557803919523772475e8ea3",
|
||||
"reference": "fcd87520e4943d968557803919523772475e8ea3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.6 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1",
|
||||
"squizlabs/php_codesniffer": "^3.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev",
|
||||
"dev-develop": "1.1.x-dev"
|
||||
},
|
||||
"laminas": {
|
||||
"module": "Laminas\\ZendFrameworkBridge"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/autoload.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Laminas\\ZendFrameworkBridge\\": "src//"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"description": "Alias legacy ZF class names to Laminas Project equivalents.",
|
||||
"keywords": [
|
||||
"ZendFramework",
|
||||
"autoloading",
|
||||
"laminas",
|
||||
"zf"
|
||||
],
|
||||
"time": "2020-05-20T16:45:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/fast-route",
|
||||
"version": "v1.3.0",
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
meta:
|
||||
title: 'Content Elements'
|
||||
description: "There are a lot of other settings for your content area. For example: \nAdd an edit-button for github, gitlab or other plattforms.\nShow the author.\nShow the publish date.\nShow the chapter numbers in the navigation.\n"
|
||||
heroimage: null
|
||||
heroimagealt: null
|
||||
owner: testauthor
|
||||
author: trendschau
|
||||
manualdate: null
|
||||
modified: '2020-07-09'
|
||||
created: '2020-06-11'
|
||||
time: 21-05-02
|
||||
navtitle: 'content elements'
|
||||
modified: '2020-06-11'
|
||||
hide: false
|
||||
|
|
|
@ -24,6 +24,12 @@ class ArticleApiController extends ContentController
|
|||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
# minimum permission is that user can publish his own content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'publish'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to publish content.']), 403);
|
||||
}
|
||||
|
||||
# validate input only if raw mode
|
||||
if($this->params['raw'])
|
||||
{
|
||||
|
@ -35,6 +41,16 @@ class ArticleApiController extends ContentController
|
|||
|
||||
# set item
|
||||
if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
# if user has no right to update content from others (eg admin or editor)
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'publish'))
|
||||
{
|
||||
# check ownership. This code should nearly never run, because there is no button/interface to trigger it.
|
||||
if(!$this->checkContentOwnership())
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to publish content.']), 403);
|
||||
}
|
||||
}
|
||||
|
||||
# set the status for published and drafted
|
||||
$this->setPublishStatus();
|
||||
|
@ -100,12 +116,28 @@ class ArticleApiController extends ContentController
|
|||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
# minimum permission is that user can unpublish his own content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'unpublish'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to unpublish content.']), 403);
|
||||
}
|
||||
|
||||
# set structure
|
||||
if(!$this->setStructure($draft = true)){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
# set item
|
||||
if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
# if user has no right to update content from others (eg admin or editor)
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'unpublish'))
|
||||
{
|
||||
# check ownership. This code should nearly never run, because there is no button/interface to trigger it.
|
||||
if(!$this->checkContentOwnership())
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to unpublish content.']), 403);
|
||||
}
|
||||
}
|
||||
|
||||
# set the status for published and drafted
|
||||
$this->setPublishStatus();
|
||||
|
||||
|
@ -178,17 +210,32 @@ class ArticleApiController extends ContentController
|
|||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
# minimum permission is that user is allowed to update his own content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'update'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to publish content.']), 403);
|
||||
}
|
||||
|
||||
# set structure
|
||||
if(!$this->setStructure($draft = true)){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
# set item
|
||||
if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
# if user has no right to update content from others (eg admin or editor)
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'update'))
|
||||
{
|
||||
# check ownership. This code should nearly never run, because there is no button/interface to trigger it.
|
||||
if(!$this->checkContentOwnership())
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to update content.']), 403);
|
||||
}
|
||||
}
|
||||
|
||||
# remove the unpublished changes
|
||||
$delete = $this->deleteContentFiles(['txt']);
|
||||
|
||||
# set redirect url to edit page
|
||||
|
||||
$url = $this->uri->getBaseUrl() . '/tm/content/' . $this->settings['editor'];
|
||||
if(isset($this->item->urlRelWoF))
|
||||
{
|
||||
|
@ -217,6 +264,12 @@ class ArticleApiController extends ContentController
|
|||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
# minimum permission is that user is allowed to delete his own content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'delete'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to delete content.']), 403);
|
||||
}
|
||||
|
||||
# set url to base path initially
|
||||
$url = $this->uri->getBaseUrl() . '/tm/content/' . $this->settings['editor'];
|
||||
|
||||
|
@ -225,6 +278,16 @@ class ArticleApiController extends ContentController
|
|||
|
||||
# set item
|
||||
if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
# if user has no right to delete content from others (eg admin or editor)
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'delete'))
|
||||
{
|
||||
# check ownership. This code should nearly never run, because there is no button/interface to trigger it.
|
||||
if(!$this->checkContentOwnership())
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to delete content.']), 403);
|
||||
}
|
||||
}
|
||||
|
||||
if($this->item->elementType == 'file')
|
||||
{
|
||||
|
@ -275,16 +338,32 @@ class ArticleApiController extends ContentController
|
|||
# get params from call
|
||||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
# minimum permission is that user is allowed to update his own content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'update'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to update content.']), 403);
|
||||
}
|
||||
|
||||
# validate input
|
||||
if(!$this->validateEditorInput()){ return $response->withJson($this->errors,422); }
|
||||
|
||||
# set structure
|
||||
if(!$this->setStructure($draft = true)){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
|
||||
# set item
|
||||
if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
# if user has no right to delete content from others (eg admin or editor)
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'update'))
|
||||
{
|
||||
# check ownership. This code should nearly never run, because there is no button/interface to trigger it.
|
||||
if(!$this->checkContentOwnership())
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to update content.']), 403);
|
||||
}
|
||||
}
|
||||
|
||||
# set path for the file (or folder)
|
||||
$this->setItemPath('txt');
|
||||
|
||||
|
@ -319,6 +398,12 @@ class ArticleApiController extends ContentController
|
|||
# get params from call
|
||||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
# minimum permission is that user is allowed to update his own content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'update'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => 'You are not allowed to update content.'), 403);
|
||||
}
|
||||
|
||||
# url is only needed, if an active page is moved to another folder, so user has to be redirected to the new url
|
||||
$url = false;
|
||||
|
@ -339,6 +424,19 @@ class ArticleApiController extends ContentController
|
|||
|
||||
if(!$item){ return $response->withJson(array('data' => $this->structure, 'errors' => 'We could not find this page. Please refresh and try again.', 'url' => $url), 404); }
|
||||
|
||||
# needed for acl check
|
||||
$this->item = $item;
|
||||
|
||||
# if user has no right to update content from others (eg admin or editor)
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'update'))
|
||||
{
|
||||
# check ownership. This code should nearly never run, because there is no button/interface to trigger it.
|
||||
if(!$this->checkContentOwnership())
|
||||
{
|
||||
return $response->withJson(array('data' => $this->structure, 'errors' => 'You are not allowed to move that content.'), 403);
|
||||
}
|
||||
}
|
||||
|
||||
# if an item is moved to the first level
|
||||
if($this->params['parent_id_to'] == 'navi')
|
||||
{
|
||||
|
@ -397,7 +495,7 @@ class ArticleApiController extends ContentController
|
|||
}
|
||||
$index++;
|
||||
}
|
||||
if($writeError){ return $response->withJson(array('data' => $this->structure, 'errors' => 'Something went wrong. Please refresh the page and check, if all folders and files are writable.', 'url' => $url), 404); }
|
||||
if($writeError){ return $response->withJson(array('data' => $this->structure, 'errors' => ['message' => 'Something went wrong. Please refresh the page and check, if all folders and files are writable.'], 'url' => $url), 404); }
|
||||
|
||||
# update the structure for editor
|
||||
$this->setStructure($draft = true, $cache = false);
|
||||
|
@ -427,6 +525,12 @@ class ArticleApiController extends ContentController
|
|||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
# minimum permission is that user is allowed to update his own content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'create'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to create content.']), 403);
|
||||
}
|
||||
|
||||
# url is only needed, if an active page is moved
|
||||
$url = false;
|
||||
|
||||
|
@ -434,7 +538,7 @@ class ArticleApiController extends ContentController
|
|||
if(!$this->setStructure($draft = true)){ return $response->withJson(array('data' => false, 'errors' => $this->errors, 'url' => $url), 404); }
|
||||
|
||||
# validate input
|
||||
if(!$this->validateNaviItem()){ return $response->withJson(array('data' => $this->structure, 'errors' => 'Special Characters not allowed. Length between 1 and 60 chars.', 'url' => $url), 422); }
|
||||
if(!$this->validateNaviItem()){ return $response->withJson(array('data' => $this->structure, 'errors' => ['message' => 'Special Characters not allowed. Length between 1 and 60 chars.'], 'url' => $url), 422); }
|
||||
|
||||
# get the ids (key path) for item, old folder and new folder
|
||||
$folderKeyPath = explode('.', $this->params['folder_id']);
|
||||
|
@ -442,7 +546,7 @@ class ArticleApiController extends ContentController
|
|||
# get the item from structure
|
||||
$folder = Folder::getItemWithKeyPath($this->structure, $folderKeyPath);
|
||||
|
||||
if(!$folder){ return $response->withJson(array('data' => $this->structure, 'errors' => 'We could not find this page. Please refresh and try again.', 'url' => $url), 404); }
|
||||
if(!$folder){ return $response->withJson(array('data' => $this->structure, 'errors' => ['message' => 'We could not find this page. Please refresh and try again.'], 'url' => $url), 404); }
|
||||
|
||||
$name = $this->params['item_name'];
|
||||
$slug = URLify::filter(iconv(mb_detect_encoding($this->params['item_name'], mb_detect_order(), true), "UTF-8", $this->params['item_name']));
|
||||
|
@ -464,7 +568,6 @@ class ArticleApiController extends ContentController
|
|||
return $response->withJson(array('data' => $this->structure, 'errors' => 'We could not create the file. Please refresh the page and check, if all folders and files are writable.', 'url' => $url), 404);
|
||||
}
|
||||
|
||||
|
||||
# get extended structure
|
||||
$extended = $write->getYaml('cache', 'structure-extended.yaml');
|
||||
|
||||
|
@ -494,6 +597,12 @@ class ArticleApiController extends ContentController
|
|||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
# minimum permission is that user is allowed to update his own content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'create'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to create content.']), 403);
|
||||
}
|
||||
|
||||
# url is only needed, if an active page is moved
|
||||
$url = false;
|
||||
|
||||
|
@ -608,6 +717,12 @@ class ArticleApiController extends ContentController
|
|||
# get params from call
|
||||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
# minimum permission is that user is allowed to update his own content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'create'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => 'You are not allowed to create content.'), 403);
|
||||
}
|
||||
|
||||
# url is only needed, if an active page is moved
|
||||
$url = false;
|
||||
|
@ -730,12 +845,28 @@ class ArticleApiController extends ContentController
|
|||
/* get params from call */
|
||||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
|
||||
# minimum permission is that user is allowed to update his own content. This will completely disable the block-editor
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'update'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => 'You are not allowed to edit content.'), 403);
|
||||
}
|
||||
|
||||
# set structure
|
||||
if(!$this->setStructure($draft = true)){ return $response->withJson(array('data' => false, 'errors' => $this->errors), 404); }
|
||||
|
||||
/* set item */
|
||||
if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
# if user has no right to delete content from others (eg admin or editor)
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'update'))
|
||||
{
|
||||
# check ownership. This code should nearly never run, because there is no button/interface to trigger it.
|
||||
if(!$this->checkContentOwnership())
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => 'You are not allowed to delete content.'), 403);
|
||||
}
|
||||
}
|
||||
|
||||
# set the status for published and drafted
|
||||
$this->setPublishStatus();
|
||||
|
@ -778,12 +909,27 @@ class ArticleApiController extends ContentController
|
|||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'update'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => 'You are not allowed to edit content.'), 403);
|
||||
}
|
||||
|
||||
# set structure
|
||||
if(!$this->setStructure($draft = true)){ return $response->withJson(array('data' => false, 'errors' => $this->errors), 404); }
|
||||
|
||||
/* set item */
|
||||
if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
|
||||
# if user has no right to delete content from others (eg admin or editor)
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'update'))
|
||||
{
|
||||
# check ownership. This code should nearly never run, because there is no button/interface to trigger it.
|
||||
if(!$this->checkContentOwnership())
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => 'You are not allowed to delete content.'), 403);
|
||||
}
|
||||
}
|
||||
|
||||
# set the status for published and drafted
|
||||
$this->setPublishStatus();
|
||||
|
||||
|
|
|
@ -125,10 +125,15 @@ class AuthController extends Controller
|
|||
$yaml->updateYaml('settings/users', '.logins', $logins);
|
||||
}
|
||||
|
||||
$settings = $this->c->get('settings');
|
||||
$editor = (isset($settings['editor']) && $settings['editor'] == 'visual') ? 'visual' : 'raw';
|
||||
|
||||
return $response->withRedirect($this->c->router->pathFor('content.' . $editor));
|
||||
# if user is allowed to view content-area
|
||||
if($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'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,12 @@ class BlockApiController extends ContentController
|
|||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
# minimum permission is that user is allowed to update his own content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'update'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to publish content.']), 403);
|
||||
}
|
||||
|
||||
/* validate input */
|
||||
if(!$this->validateBlockInput()){ return $response->withJson($this->errors,422); }
|
||||
|
||||
|
@ -30,6 +36,16 @@ class BlockApiController extends ContentController
|
|||
/* set item */
|
||||
if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
# if user has no right to delete content from others (eg admin or editor)
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'update'))
|
||||
{
|
||||
# check ownership. This code should nearly never run, because there is no button/interface to trigger it.
|
||||
if(!$this->checkContentOwnership())
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to edit content.']), 403);
|
||||
}
|
||||
}
|
||||
|
||||
# set the status for published and drafted
|
||||
$this->setPublishStatus();
|
||||
|
||||
|
@ -77,7 +93,7 @@ class BlockApiController extends ContentController
|
|||
elseif(($this->params['block_id'] == 0) OR !isset($pageMarkdown[$this->params['block_id']]))
|
||||
{
|
||||
# if the block does not exists, return an error
|
||||
return $response->withJson(array('data' => false, 'errors' => 'The ID of the content-block is wrong.'), 404);
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'The ID of the content-block is wrong.']), 404);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -201,6 +217,12 @@ class BlockApiController extends ContentController
|
|||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
# minimum permission is that user is allowed to update his own content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'update'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to publish content.']), 403);
|
||||
}
|
||||
|
||||
/* validate input */
|
||||
if(!$this->validateBlockInput()){ return $response->withJson($this->errors,422); }
|
||||
|
||||
|
@ -210,6 +232,16 @@ class BlockApiController extends ContentController
|
|||
/* set item */
|
||||
if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
# if user has no right to delete content from others (eg admin or editor)
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'update'))
|
||||
{
|
||||
# check ownership. This code should nearly never run, because there is no button/interface to trigger it.
|
||||
if(!$this->checkContentOwnership())
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to edit content.']), 403);
|
||||
}
|
||||
}
|
||||
|
||||
# set the status for published and drafted
|
||||
$this->setPublishStatus();
|
||||
|
||||
|
@ -249,7 +281,7 @@ class BlockApiController extends ContentController
|
|||
if(!isset($pageMarkdown[$this->params['block_id']]))
|
||||
{
|
||||
# if the block does not exists, return an error
|
||||
return $response->withJson(array('data' => false, 'errors' => 'The ID of the content-block is wrong.'), 404);
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'The ID of the content-block is wrong.']), 404);
|
||||
}
|
||||
elseif($this->params['block_id'] == 0)
|
||||
{
|
||||
|
@ -340,6 +372,12 @@ class BlockApiController extends ContentController
|
|||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
# minimum permission is that user is allowed to update his own content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'update'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to publish content.']), 403);
|
||||
}
|
||||
|
||||
# validate input
|
||||
# if(!$this->validateBlockInput()){ return $response->withJson($this->errors,422); }
|
||||
|
||||
|
@ -349,6 +387,16 @@ class BlockApiController extends ContentController
|
|||
# set item
|
||||
if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
# if user has no right to delete content from others (eg admin or editor)
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'update'))
|
||||
{
|
||||
# check ownership. This code should nearly never run, because there is no button/interface to trigger it.
|
||||
if(!$this->checkContentOwnership())
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to delete content.']), 403);
|
||||
}
|
||||
}
|
||||
|
||||
# set the status for published and drafted
|
||||
$this->setPublishStatus();
|
||||
|
||||
|
@ -382,7 +430,7 @@ class BlockApiController extends ContentController
|
|||
if(!isset($pageMarkdown[$oldIndex]))
|
||||
{
|
||||
# if the block does not exists, return an error
|
||||
return $response->withJson(array('data' => false, 'errors' => 'The ID of the content-block is wrong.'), 404);
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'The ID of the content-block is wrong.']), 404);
|
||||
}
|
||||
|
||||
$extract = array_splice($pageMarkdown, $oldIndex, 1);
|
||||
|
@ -432,6 +480,12 @@ class BlockApiController extends ContentController
|
|||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
$errors = false;
|
||||
|
||||
# minimum permission is that user is allowed to update his own content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'update'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to publish content.']), 403);
|
||||
}
|
||||
|
||||
# set structure
|
||||
if(!$this->setStructure($draft = true)){ return $response->withJson(array('data' => false, 'errors' => $this->errors), 404); }
|
||||
|
@ -439,6 +493,16 @@ class BlockApiController extends ContentController
|
|||
# set item
|
||||
if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
# if user has no right to delete content from others (eg admin or editor)
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'update'))
|
||||
{
|
||||
# check ownership. This code should nearly never run, because there is no button/interface to trigger it.
|
||||
if(!$this->checkContentOwnership())
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to delete content.']), 403);
|
||||
}
|
||||
}
|
||||
|
||||
# set the status for published and drafted
|
||||
$this->setPublishStatus();
|
||||
|
||||
|
@ -616,7 +680,7 @@ class BlockApiController extends ContentController
|
|||
return $response->withJson(array('errors' => false));
|
||||
}
|
||||
|
||||
return $response->withJson(array('errors' => 'could not store image to temporary folder'));
|
||||
return $response->withJson(array('errors' => ['message' => 'could not store image to temporary folder']));
|
||||
}
|
||||
|
||||
public function createFile(Request $request, Response $response, $args)
|
||||
|
@ -632,7 +696,7 @@ class BlockApiController extends ContentController
|
|||
$allowedMimes = $this->getAllowedMtypes();
|
||||
if(!in_array($mtype, $allowedMimes))
|
||||
{
|
||||
return $response->withJson(array('errors' => 'File-type is not allowed'));
|
||||
return $response->withJson(array('errors' => ['message' => 'File-type is not allowed']));
|
||||
}
|
||||
|
||||
# sanitize file name
|
||||
|
@ -653,7 +717,7 @@ class BlockApiController extends ContentController
|
|||
return $response->withJson(array('errors' => false, 'name' => $name));
|
||||
}
|
||||
|
||||
return $response->withJson(array('errors' => 'could not store file to temporary folder'));
|
||||
return $response->withJson(array('errors' => ['message' => 'could not store file to temporary folder']));
|
||||
}
|
||||
|
||||
public function publishImage(Request $request, Response $response, $args)
|
||||
|
@ -681,7 +745,7 @@ class BlockApiController extends ContentController
|
|||
return $this->updateBlock($request, $response, $args);
|
||||
}
|
||||
|
||||
return $response->withJson(array('errors' => 'could not store image to media folder'));
|
||||
return $response->withJson(array('errors' => ['message' => 'could not store image to media folder']));
|
||||
}
|
||||
|
||||
public function deleteImage(Request $request, Response $response, $args)
|
||||
|
@ -692,7 +756,7 @@ class BlockApiController extends ContentController
|
|||
|
||||
if(!isset($this->params['name']))
|
||||
{
|
||||
return $response->withJson(array('errors' => 'image name is missing'));
|
||||
return $response->withJson(array('errors' => ['message' => 'image name is missing']));
|
||||
}
|
||||
|
||||
$imageProcessor = new ProcessImage($this->settings['images']);
|
||||
|
@ -714,7 +778,7 @@ class BlockApiController extends ContentController
|
|||
|
||||
if(!isset($this->params['name']))
|
||||
{
|
||||
return $response->withJson(array('errors' => 'file name is missing'));
|
||||
return $response->withJson(array('errors' => ['message' => 'file name is missing']));
|
||||
}
|
||||
|
||||
$fileProcessor = new ProcessFile();
|
||||
|
@ -725,7 +789,7 @@ class BlockApiController extends ContentController
|
|||
return $response->withJson(array('errors' => false));
|
||||
}
|
||||
|
||||
return $response->withJson(array('errors' => 'could not delete the file'));
|
||||
return $response->withJson(array('errors' => ['message' => 'could not delete the file']));
|
||||
}
|
||||
|
||||
public function saveVideoImage(Request $request, Response $response, $args)
|
||||
|
@ -803,7 +867,7 @@ class BlockApiController extends ContentController
|
|||
return $this->updateBlock($request, $response, $args);
|
||||
}
|
||||
|
||||
return $response->withJson(array('errors' => 'could not store the preview image'));
|
||||
return $response->withJson(array('errors' => ['message' => 'could not store the preview image']));
|
||||
}
|
||||
|
||||
private function getAllowedMtypes()
|
||||
|
@ -828,6 +892,7 @@ class BlockApiController extends ContentController
|
|||
'application/pdf',
|
||||
'image/png',
|
||||
'image/jpeg',
|
||||
'image/jpg',
|
||||
'image/gif',
|
||||
'image/svg+xml',
|
||||
'font/*',
|
||||
|
|
|
@ -32,6 +32,9 @@ class ContentBackendController extends ContentController
|
|||
|
||||
# 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->structure, $this->item->keyPathArray) : false;
|
||||
|
@ -75,7 +78,16 @@ class ContentBackendController extends ContentController
|
|||
}
|
||||
}
|
||||
|
||||
return $this->render($response, 'editor/editor-raw.twig', array('navigation' => $this->structure, 'homepage' => $this->homepage, 'title' => $title, 'content' => $content, 'item' => $this->item, 'settings' => $this->settings ));
|
||||
return $this->render($response, 'editor/editor-raw.twig', array(
|
||||
'acl' => $this->c->acl,
|
||||
'mycontent' => $this->mycontent,
|
||||
'navigation' => $this->structure,
|
||||
'homepage' => $this->homepage,
|
||||
'title' => $title,
|
||||
'content' => $content,
|
||||
'item' => $this->item,
|
||||
'settings' => $this->settings
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -101,6 +113,9 @@ class ContentBackendController extends ContentController
|
|||
# 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();
|
||||
|
||||
# set the status for published and drafted
|
||||
$this->setPublishStatus();
|
||||
|
||||
|
@ -153,7 +168,16 @@ class ContentBackendController extends ContentController
|
|||
unset($content[0]);
|
||||
}
|
||||
|
||||
return $this->render($response, 'editor/editor-blox.twig', array('navigation' => $this->structure, 'homepage' => $this->homepage, 'title' => $title, 'content' => $content, 'item' => $this->item, 'settings' => $this->settings ));
|
||||
return $this->render($response, 'editor/editor-blox.twig', array(
|
||||
'acl' => $this->c->acl,
|
||||
'mycontent' => $this->mycontent,
|
||||
'navigation' => $this->structure,
|
||||
'homepage' => $this->homepage,
|
||||
'title' => $title,
|
||||
'content' => $content,
|
||||
'item' => $this->item,
|
||||
'settings' => $this->settings
|
||||
));
|
||||
}
|
||||
|
||||
public function showEmpty(Request $request, Response $response, $args)
|
||||
|
|
|
@ -10,6 +10,7 @@ use Typemill\Models\Folder;
|
|||
use Typemill\Models\Write;
|
||||
use Typemill\Models\WriteCache;
|
||||
use Typemill\Models\WriteYaml;
|
||||
use Typemill\Models\WriteMeta;
|
||||
|
||||
abstract class ContentController
|
||||
{
|
||||
|
@ -51,6 +52,9 @@ abstract class ContentController
|
|||
|
||||
# holds the content of the page
|
||||
protected $content;
|
||||
|
||||
# holds the ownership (my content or not my content)
|
||||
protected $mycontent = false;
|
||||
|
||||
public function __construct(ContainerInterface $c)
|
||||
{
|
||||
|
@ -432,4 +436,19 @@ abstract class ContentController
|
|||
$this->content = $content;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function checkContentOwnership()
|
||||
{
|
||||
# get page meta
|
||||
$writeMeta = new writeMeta();
|
||||
$pagemeta = $writeMeta->getPageMeta($this->settings, $this->item);
|
||||
|
||||
# owner assertion, not
|
||||
if(isset($pagemeta['meta']['owner']) && $pagemeta['meta']['owner'] == $_SESSION['user'])
|
||||
{
|
||||
$this->mycontent = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -207,6 +207,12 @@ class MediaApiController extends ContentController
|
|||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
# minimum permission is that user is allowed to delete content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'delete'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => 'You are not allowed to delete images.'), 403);
|
||||
}
|
||||
|
||||
if(!isset($this->params['name']))
|
||||
{
|
||||
return $response->withJson(['errors' => 'image name is missing'],500);
|
||||
|
@ -232,6 +238,12 @@ class MediaApiController extends ContentController
|
|||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
# minimum permission is that user is allowed to delete content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'delete'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => 'You are not allowed to delete files.'), 403);
|
||||
}
|
||||
|
||||
if(!isset($this->params['name']))
|
||||
{
|
||||
return $response->withJson(['errors' => 'file name is missing'],500);
|
||||
|
|
|
@ -134,6 +134,12 @@ class MetaApiController extends ContentController
|
|||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
|
||||
# minimum permission is that user is allowed to update his own content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'update'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to update content.']), 403);
|
||||
}
|
||||
|
||||
$tab = isset($this->params['tab']) ? $this->params['tab'] : false;
|
||||
$metaInput = isset($this->params['data']) ? $this->params['data'] : false ;
|
||||
$objectName = 'meta';
|
||||
|
@ -150,6 +156,16 @@ class MetaApiController extends ContentController
|
|||
# set item
|
||||
if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
# if user has no right to delete content from others (eg admin or editor)
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'update'))
|
||||
{
|
||||
# check ownership. This code should nearly never run, because there is no button/interface to trigger it.
|
||||
if(!$this->checkContentOwnership())
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => ['message' => 'You are not allowed to edit content.']), 403);
|
||||
}
|
||||
}
|
||||
|
||||
# if item is a folder
|
||||
if($this->item->elementType == "folder")
|
||||
{
|
||||
|
|
|
@ -9,6 +9,8 @@ use Typemill\Models\Validation;
|
|||
use Typemill\Models\User;
|
||||
use Typemill\Models\ProcessFile;
|
||||
use Typemill\Models\ProcessImage;
|
||||
use Typemill\Events\OnUserfieldsLoaded;
|
||||
use Typemill\Events\OnSystemnaviLoaded;
|
||||
|
||||
class SettingsController extends Controller
|
||||
{
|
||||
|
@ -26,26 +28,28 @@ class SettingsController extends Controller
|
|||
$locale = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? substr($_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2) : 'en';
|
||||
$users = $user->getUsers();
|
||||
$route = $request->getAttribute('route');
|
||||
$navigation = $this->getNavigation();
|
||||
|
||||
return $this->render($response, 'settings/system.twig', array('settings' => $settings, 'copyright' => $copyright, 'languages' => $languages, 'locale' => $locale, 'formats' => $defaultSettings['formats'] ,'users' => $users, 'route' => $route->getName() ));
|
||||
# set navigation active
|
||||
$navigation['System']['active'] = true;
|
||||
|
||||
return $this->render($response, 'settings/system.twig', array(
|
||||
'settings' => $settings,
|
||||
'acl' => $this->c->acl,
|
||||
'navigation' => $navigation,
|
||||
'copyright' => $copyright,
|
||||
'languages' => $languages,
|
||||
'locale' => $locale,
|
||||
'formats' => $defaultSettings['formats'],
|
||||
'users' => $users,
|
||||
'route' => $route->getName()
|
||||
));
|
||||
}
|
||||
|
||||
public function saveSettings($request, $response, $args)
|
||||
{
|
||||
if($request->isPost())
|
||||
{
|
||||
$referer = $request->getHeader('HTTP_REFERER');
|
||||
$uri = $request->getUri()->withUserInfo('');
|
||||
$base_url = $uri->getBaseUrl();
|
||||
|
||||
/* security, users should not be able to fake post with settings from other typemill pages.
|
||||
if(!isset($referer[0]) OR $referer[0] !== $base_url . '/tm/settings' )
|
||||
{
|
||||
$this->c->flash->addMessage('error', 'illegal referer');
|
||||
return $response->withRedirect($this->c->router->pathFor('settings.show'));
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
$settings = \Typemill\Settings::getUserSettings();
|
||||
$defaultSettings = \Typemill\Settings::getDefaultSettings();
|
||||
$params = $request->getParams();
|
||||
|
@ -232,11 +236,19 @@ class SettingsController extends Controller
|
|||
}
|
||||
|
||||
/* add the users for navigation */
|
||||
$user = new User();
|
||||
$users = $user->getUsers();
|
||||
$route = $request->getAttribute('route');
|
||||
$route = $request->getAttribute('route');
|
||||
$navigation = $this->getNavigation();
|
||||
|
||||
return $this->render($response, 'settings/themes.twig', array('settings' => $userSettings, 'themes' => $themedata, 'users' => $users, 'route' => $route->getName() ));
|
||||
# set navigation active
|
||||
$navigation['Themes']['active'] = true;
|
||||
|
||||
return $this->render($response, 'settings/themes.twig', array(
|
||||
'settings' => $userSettings,
|
||||
'acl' => $this->c->acl,
|
||||
'navigation' => $navigation,
|
||||
'themes' => $themedata,
|
||||
'route' => $route->getName()
|
||||
));
|
||||
}
|
||||
|
||||
public function showPlugins($request, $response, $args)
|
||||
|
@ -301,11 +313,19 @@ class SettingsController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
$user = new User();
|
||||
$users = $user->getUsers();
|
||||
$route = $request->getAttribute('route');
|
||||
$navigation = $this->getNavigation();
|
||||
|
||||
# set navigation active
|
||||
$navigation['Plugins']['active'] = true;
|
||||
|
||||
return $this->render($response, 'settings/plugins.twig', array('settings' => $userSettings, 'plugins' => $plugins, 'users' => $users, 'route' => $route->getName() ));
|
||||
return $this->render($response, 'settings/plugins.twig', array(
|
||||
'settings' => $userSettings,
|
||||
'acl' => $this->c->acl,
|
||||
'navigation' => $navigation,
|
||||
'plugins' => $plugins,
|
||||
'route' => $route->getName()
|
||||
));
|
||||
}
|
||||
|
||||
/*************************************
|
||||
|
@ -315,19 +335,7 @@ class SettingsController extends Controller
|
|||
public function saveThemes($request, $response, $args)
|
||||
{
|
||||
if($request->isPost())
|
||||
{
|
||||
$referer = $request->getHeader('HTTP_REFERER');
|
||||
$uri = $request->getUri()->withUserInfo('');
|
||||
$base_url = $uri->getBaseUrl();
|
||||
|
||||
/* users should not be able to fake post with settings from other typemill pages.
|
||||
if(!isset($referer[0]) OR $referer[0] !== $base_url . '/tm/themes' )
|
||||
{
|
||||
$this->c->flash->addMessage('error', 'illegal referer');
|
||||
return $response->withRedirect($this->c->router->pathFor('themes.show'));
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
$userSettings = \Typemill\Settings::getUserSettings();
|
||||
$params = $request->getParams();
|
||||
$themeName = isset($params['theme']) ? $params['theme'] : false;
|
||||
|
@ -414,18 +422,6 @@ class SettingsController extends Controller
|
|||
{
|
||||
if($request->isPost())
|
||||
{
|
||||
$referer = $request->getHeader('HTTP_REFERER');
|
||||
$uri = $request->getUri()->withUserInfo('');
|
||||
$base_url = $uri->getBaseUrl();
|
||||
|
||||
/* security, users should not be able to fake post with settings from other typemill pages.
|
||||
if(!isset($referer[0]) OR $referer[0] !== $base_url . '/tm/plugins' )
|
||||
{
|
||||
$this->c->flash->addMessage('error', 'illegal referer');
|
||||
return $response->withRedirect($this->c->router->pathFor('plugins.show'));
|
||||
}
|
||||
*/
|
||||
|
||||
$userSettings = \Typemill\Settings::getUserSettings();
|
||||
$pluginSettings = array();
|
||||
$userInput = $request->getParams();
|
||||
|
@ -485,10 +481,428 @@ class SettingsController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
private function validateInput($objectType, $objectName, $userInput, $validate)
|
||||
/***********************
|
||||
** USER MANAGEMENT **
|
||||
***********************/
|
||||
|
||||
public function showAccount($request, $response, $args)
|
||||
{
|
||||
/* fetch the original settings from the folder (plugin or theme) to get the field definitions */
|
||||
$originalSettings = \Typemill\Settings::getObjectSettings($objectType, $objectName);
|
||||
$username = $_SESSION['user'];
|
||||
|
||||
$validate = new Validation();
|
||||
|
||||
if($validate->username($username))
|
||||
{
|
||||
# get settings
|
||||
$settings = $this->c->get('settings');
|
||||
|
||||
# get user with userdata
|
||||
$user = new User();
|
||||
$userdata = $user->getSecureUser($username);
|
||||
|
||||
# instantiate field-builder
|
||||
$fieldsModel = new Fields();
|
||||
|
||||
# get the field-definitions
|
||||
$fieldDefinitions = $this->getUserFields($userdata['userrole']);
|
||||
|
||||
# prepare userdata for field-builder
|
||||
$userSettings['users']['user'] = $userdata;
|
||||
|
||||
# generate the input form
|
||||
$userform = $fieldsModel->getFields($userSettings, 'users', 'user', $fieldDefinitions);
|
||||
|
||||
$route = $request->getAttribute('route');
|
||||
$navigation = $this->getNavigation();
|
||||
|
||||
# set navigation active
|
||||
$navigation['Account']['active'] = true;
|
||||
|
||||
return $this->render($response, 'settings/user.twig', array(
|
||||
'settings' => $settings,
|
||||
'acl' => $this->c->acl,
|
||||
'navigation' => $navigation,
|
||||
'usersettings' => $userSettings, // needed for image url in form, will overwrite settings for field-template
|
||||
'userform' => $userform, // field model, needed to generate frontend-field
|
||||
'userdata' => $userdata, // needed to fill form with data
|
||||
# 'userrole' => false, // not needed ?
|
||||
# 'username' => $args['username'], // not needed ?
|
||||
'route' => $route->getName() // needed to set link active
|
||||
));
|
||||
}
|
||||
|
||||
$this->c->flash->addMessage('error', 'User does not exists');
|
||||
return $response->withRedirect($this->c->router->pathFor('home'));
|
||||
}
|
||||
|
||||
public function showUser($request, $response, $args)
|
||||
{
|
||||
# if user has no rights to watch userlist, then redirect to
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'userlist', 'view') && $_SESSION['user'] !== $args['username'] )
|
||||
{
|
||||
return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $_SESSION['user']] ));
|
||||
}
|
||||
|
||||
$validate = new Validation();
|
||||
|
||||
if($validate->username($args['username']))
|
||||
{
|
||||
# get settings
|
||||
$settings = $this->c->get('settings');
|
||||
|
||||
# get user with userdata
|
||||
$user = new User();
|
||||
$userdata = $user->getSecureUser($args['username']);
|
||||
|
||||
$username = $userdata['username'];
|
||||
|
||||
# instantiate field-builder
|
||||
$fieldsModel = new Fields();
|
||||
|
||||
# get the field-definitions
|
||||
$fieldDefinitions = $this->getUserFields($userdata['userrole']);
|
||||
|
||||
# prepare userdata for field-builder
|
||||
$userSettings['users']['user'] = $userdata;
|
||||
|
||||
# generate the input form
|
||||
$userform = $fieldsModel->getFields($userSettings, 'users', 'user', $fieldDefinitions);
|
||||
|
||||
$route = $request->getAttribute('route');
|
||||
$navigation = $this->getNavigation();
|
||||
|
||||
# set navigation active
|
||||
$navigation['Users']['active'] = true;
|
||||
|
||||
return $this->render($response, 'settings/user.twig', array(
|
||||
'settings' => $settings,
|
||||
'acl' => $this->c->acl,
|
||||
'navigation' => $navigation,
|
||||
'usersettings' => $userSettings, // needed for image url in form, will overwrite settings for field-template
|
||||
'userform' => $userform, // field model, needed to generate frontend-field
|
||||
'userdata' => $userdata, // needed to fill form with data
|
||||
# 'userrole' => false, // not needed ?
|
||||
# 'username' => $args['username'], // not needed ?
|
||||
'route' => $route->getName() // needed to set link active
|
||||
));
|
||||
}
|
||||
|
||||
$this->c->flash->addMessage('error', 'User does not exists');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.account'));
|
||||
}
|
||||
|
||||
public function listUser($request, $response)
|
||||
{
|
||||
$user = new User();
|
||||
$users = $user->getUsers();
|
||||
$userdata = array();
|
||||
$route = $request->getAttribute('route');
|
||||
$settings = $this->c->get('settings');
|
||||
$navigation = $this->getNavigation();
|
||||
|
||||
# set navigation active
|
||||
$navigation['Users']['active'] = true;
|
||||
|
||||
foreach($users as $username)
|
||||
{
|
||||
$userdata[] = $user->getUser($username);
|
||||
}
|
||||
|
||||
return $this->render($response, 'settings/userlist.twig', array(
|
||||
'settings' => $settings,
|
||||
'acl' => $this->c->acl,
|
||||
'navigation' => $navigation,
|
||||
'users' => $users,
|
||||
'userdata' => $userdata,
|
||||
'route' => $route->getName()
|
||||
));
|
||||
}
|
||||
|
||||
public function newUser($request, $response, $args)
|
||||
{
|
||||
$user = new User();
|
||||
$users = $user->getUsers();
|
||||
$userroles = $this->c->acl->getRoles();
|
||||
$route = $request->getAttribute('route');
|
||||
$settings = $this->c->get('settings');
|
||||
$navigation = $this->getNavigation();
|
||||
|
||||
# set navigation active
|
||||
$navigation['Users']['active'] = true;
|
||||
|
||||
return $this->render($response, 'settings/usernew.twig', array(
|
||||
'settings' => $settings,
|
||||
'acl' => $this->c->acl,
|
||||
'navigation' => $navigation,
|
||||
'users' => $users,
|
||||
'userrole' => $userroles,
|
||||
'route' => $route->getName()
|
||||
));
|
||||
}
|
||||
|
||||
public function createUser($request, $response, $args)
|
||||
{
|
||||
if($request->isPost())
|
||||
{
|
||||
$params = $request->getParams();
|
||||
$user = new User();
|
||||
$validate = new Validation();
|
||||
$userroles = $this->c->acl->getRoles();
|
||||
|
||||
if($validate->newUser($params, $userroles))
|
||||
{
|
||||
$userdata = array(
|
||||
'username' => $params['username'],
|
||||
'email' => $params['email'],
|
||||
'userrole' => $params['userrole'],
|
||||
'password' => $params['password']);
|
||||
|
||||
$user->createUser($userdata);
|
||||
|
||||
$this->c->flash->addMessage('info', 'Welcome, there is a new user!');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.list'));
|
||||
}
|
||||
|
||||
$this->c->flash->addMessage('error', 'Please correct your input');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.new'));
|
||||
}
|
||||
}
|
||||
|
||||
public function updateUser($request, $response, $args)
|
||||
{
|
||||
|
||||
if($request->isPost())
|
||||
{
|
||||
$params = $request->getParams();
|
||||
$userdata = $params['user'];
|
||||
$user = new User();
|
||||
$validate = new Validation();
|
||||
$userroles = $this->c->acl->getRoles();
|
||||
|
||||
$redirectRoute = ($userdata['username'] == $_SESSION['user']) ? $this->c->router->pathFor('user.account') : $this->c->router->pathFor('user.show', ['username' => $userdata['username']]);
|
||||
|
||||
# check if user is allowed to view (edit) userlist and other users
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'userlist', 'write'))
|
||||
{
|
||||
# if an editor tries to update other userdata than its own */
|
||||
if($_SESSION['user'] !== $userdata['username'])
|
||||
{
|
||||
return $response->withRedirect($this->c->router->pathFor('user.account'));
|
||||
}
|
||||
|
||||
# non admins cannot change their userrole, so set it to session-value
|
||||
$userdata['userrole'] = $_SESSION['role'];
|
||||
}
|
||||
|
||||
# validate standard fields for users
|
||||
if($validate->existingUser($userdata, $userroles))
|
||||
{
|
||||
# validate custom input fields and return images
|
||||
$userfields = $this->getUserFields($userdata['userrole']);
|
||||
$imageFields = $this->validateInput('users', 'user', $userdata, $validate, $userfields);
|
||||
|
||||
if(!empty($imageFields))
|
||||
{
|
||||
$images = $request->getUploadedFiles();
|
||||
|
||||
if(isset($images['user']))
|
||||
{
|
||||
# set image size
|
||||
$settings = $this->c->get('settings');
|
||||
$settings->replace(['images' => ['live' => ['width' => 500, 'height' => 500]]]);
|
||||
$imageresult = $this->saveImages($imageFields, $userdata, $settings, $images['user']);
|
||||
|
||||
if(isset($_SESSION['slimFlash']['error']))
|
||||
{
|
||||
return $response->withRedirect($redirectRoute);
|
||||
}
|
||||
elseif(isset($imageresult['username']))
|
||||
{
|
||||
$userdata = $imageresult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# check for errors and redirect to path, if errors found */
|
||||
if(isset($_SESSION['errors']))
|
||||
{
|
||||
$this->c->flash->addMessage('error', 'Please correct the errors');
|
||||
return $response->withRedirect($redirectRoute);
|
||||
}
|
||||
|
||||
if(empty($userdata['password']) AND empty($userdata['newpassword']))
|
||||
{
|
||||
# make sure no invalid passwords go into model
|
||||
unset($userdata['password']);
|
||||
unset($userdata['newpassword']);
|
||||
|
||||
$user->updateUser($userdata);
|
||||
$this->c->flash->addMessage('info', 'Saved all changes');
|
||||
return $response->withRedirect($redirectRoute);
|
||||
}
|
||||
elseif($validate->newPassword($userdata))
|
||||
{
|
||||
$userdata['password'] = $userdata['newpassword'];
|
||||
unset($userdata['newpassword']);
|
||||
|
||||
$user->updateUser($userdata);
|
||||
$this->c->flash->addMessage('info', 'Saved all changes');
|
||||
return $response->withRedirect($redirectRoute);
|
||||
}
|
||||
}
|
||||
|
||||
$this->c->flash->addMessage('error', 'Please correct your input');
|
||||
return $response->withRedirect($redirectRoute);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteUser($request, $response, $args)
|
||||
{
|
||||
if($request->isPost())
|
||||
{
|
||||
$params = $request->getParams();
|
||||
$validate = new Validation();
|
||||
$user = new User();
|
||||
|
||||
# check if user is allowed to view (edit) userlist and other users
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'userlist', 'write'))
|
||||
{
|
||||
# if an editor tries to delete other user than its own
|
||||
if($_SESSION['user'] !== $params['username'])
|
||||
{
|
||||
return $response->withRedirect($this->c->router->pathFor('user.account'));
|
||||
}
|
||||
}
|
||||
|
||||
if($validate->username($params['username']))
|
||||
{
|
||||
$user->deleteUser($params['username']);
|
||||
|
||||
# if user deleted his own account
|
||||
if($_SESSION['user'] == $params['username'])
|
||||
{
|
||||
session_destroy();
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
}
|
||||
|
||||
$this->c->flash->addMessage('info', 'Say goodbye, the user is gone!');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.list'));
|
||||
}
|
||||
|
||||
$this->c->flash->addMessage('error', 'Ups, we did not find that user');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $params['username']]));
|
||||
}
|
||||
}
|
||||
|
||||
private function getUserFields($role)
|
||||
{
|
||||
$fields = [];
|
||||
$fields['username'] = ['label' => 'Username (read only)', 'type' => 'text', 'readonly' => true];
|
||||
$fields['firstname'] = ['label' => 'First Name', 'type' => 'text'];
|
||||
$fields['lastname'] = ['label' => 'Last Name', 'type' => 'text'];
|
||||
$fields['email'] = ['label' => 'E-Mail', 'type' => 'text', 'required' => true];
|
||||
$fields['userrole'] = ['label' => 'Role', 'type' => 'text', 'readonly' => true];
|
||||
$fields['password'] = ['label' => 'Actual Password', 'type' => 'password'];
|
||||
$fields['newpassword'] = ['label' => 'New Password', 'type' => 'password'];
|
||||
|
||||
# dispatch fields;
|
||||
$fields = $this->c->dispatcher->dispatch('onUserfieldsLoaded', new OnUserfieldsLoaded($fields))->getData();
|
||||
|
||||
# only roles who can edit content need profile image and description
|
||||
if($this->c->acl->isAllowed($role, 'content', 'create'))
|
||||
{
|
||||
$newfield['image'] = ['label' => 'Profile-Image', 'type' => 'image'];
|
||||
$newfield['description'] = ['label' => 'Author-Description (Markdown)', 'type' => 'textarea'];
|
||||
array_splice($fields,1,0,$newfield);
|
||||
}
|
||||
|
||||
# Only admin can change userroles
|
||||
if($this->c->acl->isAllowed($_SESSION['role'], 'userlist', 'write'))
|
||||
{
|
||||
$userroles = $this->c->acl->getRoles();
|
||||
$options = [];
|
||||
|
||||
# we need associative array to make select-field with key/value work
|
||||
foreach($userroles as $userrole)
|
||||
{
|
||||
$options[$userrole] = $userrole;
|
||||
}
|
||||
|
||||
$fields['userrole'] = ['label' => 'Role', 'type' => 'select', 'options' => $options];
|
||||
}
|
||||
|
||||
$userform = [];
|
||||
$userform['forms']['fields'] = $fields;
|
||||
return $userform;
|
||||
}
|
||||
|
||||
private function getThemes()
|
||||
{
|
||||
$themeFolder = $this->c->get('settings')['rootPath'] . $this->c->get('settings')['themeFolder'];
|
||||
$themeFolderC = scandir($themeFolder);
|
||||
$themes = array();
|
||||
foreach ($themeFolderC as $key => $theme)
|
||||
{
|
||||
if (!in_array($theme, array(".","..")))
|
||||
{
|
||||
if (is_dir($themeFolder . DIRECTORY_SEPARATOR . $theme))
|
||||
{
|
||||
$themes[] = $theme;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $themes;
|
||||
}
|
||||
|
||||
private function getCopyright()
|
||||
{
|
||||
return array(
|
||||
"©",
|
||||
"CC-BY",
|
||||
"CC-BY-NC",
|
||||
"CC-BY-NC-ND",
|
||||
"CC-BY-NC-SA",
|
||||
"CC-BY-ND",
|
||||
"CC-BY-SA",
|
||||
"None"
|
||||
);
|
||||
}
|
||||
|
||||
private function getLanguages()
|
||||
{
|
||||
return array(
|
||||
'en' => 'English',
|
||||
'ru' => 'Russian',
|
||||
'nl' => 'Dutch, Flemish',
|
||||
'de' => 'German',
|
||||
'it' => 'Italian',
|
||||
'fr' => 'French',
|
||||
);
|
||||
}
|
||||
|
||||
private function getNavigation()
|
||||
{
|
||||
$navigation = [
|
||||
'System' => ['routename' => 'settings.show', 'icon' => 'icon-wrench', 'aclresource' => 'system', 'aclprivilege' => 'view'],
|
||||
'Themes' => ['routename' => 'themes.show', 'icon' => 'icon-paint-brush', 'aclresource' => 'system', 'aclprivilege' => 'view'],
|
||||
'Plugins' => ['routename' => 'plugins.show', 'icon' => 'icon-plug', 'aclresource' => 'system', 'aclprivilege' => 'view'],
|
||||
'Account' => ['routename' => 'user.account', 'icon' => 'icon-user', 'aclresource' => 'user', 'aclprivilege' => 'view'],
|
||||
'Users' => ['routename' => 'user.list', 'icon' => 'icon-group', 'aclresource' => 'userlist', 'aclprivilege' => 'view']
|
||||
];
|
||||
|
||||
# dispatch fields;
|
||||
$navigation = $this->c->dispatcher->dispatch('onSystemnaviLoaded', new OnSystemnaviLoaded($navigation))->getData();
|
||||
|
||||
return $navigation;
|
||||
}
|
||||
|
||||
private function validateInput($objectType, $objectName, $userInput, $validate, $originalSettings = NULL)
|
||||
{
|
||||
if(!$originalSettings)
|
||||
{
|
||||
# fetch the original settings from the folder (plugin or theme) to get the field definitions
|
||||
$originalSettings = \Typemill\Settings::getObjectSettings($objectType, $objectName);
|
||||
}
|
||||
|
||||
# images get special treatment
|
||||
$imageFieldDefinitions = array();
|
||||
|
@ -544,7 +958,7 @@ class SettingsController extends Controller
|
|||
$imageFieldDefinitions[$fieldName] = $fieldDefinition;
|
||||
}
|
||||
}
|
||||
if(!$fieldDefinition && $fieldName != 'active')
|
||||
if(!$fieldDefinition && $objectType != 'users' && $fieldName != 'active')
|
||||
{
|
||||
$_SESSION['errors'][$objectName][$fieldName] = array('This field is not defined!');
|
||||
}
|
||||
|
@ -560,7 +974,7 @@ class SettingsController extends Controller
|
|||
# initiate image processor with standard image sizes
|
||||
$processImages = new ProcessImage($userSettings['images']);
|
||||
|
||||
if(!$processImages->checkFolders())
|
||||
if(!$processImages->checkFolders('images'))
|
||||
{
|
||||
$this->c->flash->addMessage('error', 'Please make sure that your media folder exists and is writable.');
|
||||
return false;
|
||||
|
@ -589,251 +1003,5 @@ class SettingsController extends Controller
|
|||
}
|
||||
}
|
||||
return $userInput;
|
||||
}
|
||||
|
||||
/***********************
|
||||
** USER MANAGEMENT **
|
||||
***********************/
|
||||
|
||||
public function showUser($request, $response, $args)
|
||||
{
|
||||
if($_SESSION['role'] == 'editor' && $_SESSION['user'] !== $args['username'])
|
||||
{
|
||||
return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $_SESSION['user']] ));
|
||||
}
|
||||
|
||||
$validate = new Validation();
|
||||
|
||||
if($validate->username($args['username']))
|
||||
{
|
||||
$user = new User();
|
||||
$users = $user->getUsers();
|
||||
$userrole = $user->getUserroles();
|
||||
$userdata = $user->getUser($args['username']);
|
||||
$settings = $this->c->get('settings');
|
||||
|
||||
if($userdata)
|
||||
{
|
||||
return $this->render($response, 'settings/user.twig', array('settings' => $settings, 'users' => $users, 'userdata' => $userdata, 'userrole' => $userrole, 'username' => $args['username'] ));
|
||||
}
|
||||
}
|
||||
|
||||
$this->c->flash->addMessage('error', 'User does not exists');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.list'));
|
||||
}
|
||||
|
||||
public function listUser($request, $response)
|
||||
{
|
||||
$user = new User();
|
||||
$users = $user->getUsers();
|
||||
$userdata = array();
|
||||
$route = $request->getAttribute('route');
|
||||
$settings = $this->c->get('settings');
|
||||
|
||||
foreach($users as $username)
|
||||
{
|
||||
$userdata[] = $user->getUser($username);
|
||||
}
|
||||
|
||||
return $this->render($response, 'settings/userlist.twig', array('settings' => $settings, 'users' => $users, 'userdata' => $userdata, 'route' => $route->getName() ));
|
||||
}
|
||||
|
||||
public function newUser($request, $response, $args)
|
||||
{
|
||||
$user = new User();
|
||||
$users = $user->getUsers();
|
||||
$userrole = $user->getUserroles();
|
||||
$route = $request->getAttribute('route');
|
||||
$settings = $this->c->get('settings');
|
||||
|
||||
return $this->render($response, 'settings/usernew.twig', array('settings' => $settings, 'users' => $users, 'userrole' => $userrole, 'route' => $route->getName() ));
|
||||
}
|
||||
|
||||
public function createUser($request, $response, $args)
|
||||
{
|
||||
if($request->isPost())
|
||||
{
|
||||
$referer = $request->getHeader('HTTP_REFERER');
|
||||
$uri = $request->getUri()->withUserInfo('');
|
||||
$base_url = $uri->getBaseUrl();
|
||||
|
||||
/* security, users should not be able to fake post with settings from other typemill pages.
|
||||
if(!isset($referer[0]) OR $referer[0] !== $base_url . '/tm/user/new' )
|
||||
{
|
||||
$this->c->flash->addMessage('error', 'illegal referer');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.new'));
|
||||
}
|
||||
*/
|
||||
|
||||
$params = $request->getParams();
|
||||
$user = new User();
|
||||
$userroles = $user->getUserroles();
|
||||
$validate = new Validation();
|
||||
|
||||
if($validate->newUser($params, $userroles))
|
||||
{
|
||||
$userdata = array('username' => $params['username'], 'firstname' => $params['firstname'], 'lastname' => $params['lastname'], 'email' => $params['email'], 'userrole' => $params['userrole'], 'password' => $params['password']);
|
||||
|
||||
$user->createUser($userdata);
|
||||
|
||||
$this->c->flash->addMessage('info', 'Welcome, there is a new user!');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.list'));
|
||||
}
|
||||
|
||||
$this->c->flash->addMessage('error', 'Please correct your input');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.new'));
|
||||
}
|
||||
}
|
||||
|
||||
public function updateUser($request, $response, $args)
|
||||
{
|
||||
if($request->isPost())
|
||||
{
|
||||
$referer = $request->getHeader('HTTP_REFERER');
|
||||
$uri = $request->getUri()->withUserInfo('');
|
||||
$base_url = $uri->getBaseUrl();
|
||||
|
||||
/* security, users should not be able to fake post with settings from other typemill pages.
|
||||
if(!isset($referer[0]) OR strpos($referer[0], $base_url . '/tm/user/') === false )
|
||||
{
|
||||
$this->c->flash->addMessage('error', 'illegal referer');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.list'));
|
||||
}
|
||||
*/
|
||||
|
||||
$params = $request->getParams();
|
||||
$user = new User();
|
||||
$userroles = $user->getUserroles();
|
||||
$validate = new Validation();
|
||||
|
||||
/* non admins have different update rights */
|
||||
if($_SESSION['role'] !== 'administrator')
|
||||
{
|
||||
/* if an editor tries to update other userdata than its own */
|
||||
if($_SESSION['user'] !== $params['username'])
|
||||
{
|
||||
return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $_SESSION['user']] ));
|
||||
}
|
||||
|
||||
/* non admins cannot change his userrole */
|
||||
$params['userrole'] = $_SESSION['role'];
|
||||
}
|
||||
|
||||
if($validate->existingUser($params, $userroles))
|
||||
{
|
||||
$userdata = array('username' => $params['username'], 'firstname' => $params['firstname'], 'lastname' => $params['lastname'], 'email' => $params['email'], 'userrole' => $params['userrole']);
|
||||
|
||||
if(empty($params['password']) AND empty($params['newpassword']))
|
||||
{
|
||||
$user->updateUser($userdata);
|
||||
$this->c->flash->addMessage('info', 'Saved all changes');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $params['username']]));
|
||||
}
|
||||
elseif($validate->newPassword($params))
|
||||
{
|
||||
$userdata['password'] = $params['newpassword'];
|
||||
$user->updateUser($userdata);
|
||||
$this->c->flash->addMessage('info', 'Saved all changes');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $params['username']]));
|
||||
}
|
||||
}
|
||||
|
||||
$this->c->flash->addMessage('error', 'Please correct your input');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $params['username']]));
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteUser($request, $response, $args)
|
||||
{
|
||||
if($request->isPost())
|
||||
{
|
||||
$referer = $request->getHeader('HTTP_REFERER');
|
||||
$uri = $request->getUri()->withUserInfo('');
|
||||
$base_url = $uri->getBaseUrl();
|
||||
|
||||
/* security, users should not be able to fake post with settings from other typemill pages.
|
||||
if(!isset($referer[0]) OR strpos($referer[0], $base_url . '/tm/user/') === false )
|
||||
{
|
||||
$this->c->flash->addMessage('error', 'illegal referer');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.list'));
|
||||
}
|
||||
*/
|
||||
|
||||
$params = $request->getParams();
|
||||
$validate = new Validation();
|
||||
$user = new User();
|
||||
|
||||
/* non admins have different update rights */
|
||||
if($_SESSION['role'] !== 'administrator')
|
||||
{
|
||||
/* if an editor tries to delete other user than its own */
|
||||
if($_SESSION['user'] !== $params['username'])
|
||||
{
|
||||
return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $_SESSION['user']] ));
|
||||
}
|
||||
}
|
||||
|
||||
if($validate->username($params['username']))
|
||||
{
|
||||
$user->deleteUser($params['username']);
|
||||
|
||||
# if user deleted his own account
|
||||
if($_SESSION['user'] == $params['username'])
|
||||
{
|
||||
session_destroy();
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
}
|
||||
|
||||
$this->c->flash->addMessage('info', 'Say goodbye, the user is gone!');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.list'));
|
||||
}
|
||||
|
||||
$this->c->flash->addMessage('error', 'Ups, we did not find that user');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $params['username']]));
|
||||
}
|
||||
}
|
||||
|
||||
private function getThemes()
|
||||
{
|
||||
$themeFolder = $this->c->get('settings')['rootPath'] . $this->c->get('settings')['themeFolder'];
|
||||
$themeFolderC = scandir($themeFolder);
|
||||
$themes = array();
|
||||
foreach ($themeFolderC as $key => $theme)
|
||||
{
|
||||
if (!in_array($theme, array(".","..")))
|
||||
{
|
||||
if (is_dir($themeFolder . DIRECTORY_SEPARATOR . $theme))
|
||||
{
|
||||
$themes[] = $theme;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $themes;
|
||||
}
|
||||
|
||||
private function getCopyright()
|
||||
{
|
||||
return array(
|
||||
"©",
|
||||
"CC-BY",
|
||||
"CC-BY-NC",
|
||||
"CC-BY-NC-ND",
|
||||
"CC-BY-NC-SA",
|
||||
"CC-BY-ND",
|
||||
"CC-BY-SA",
|
||||
"None"
|
||||
);
|
||||
}
|
||||
|
||||
private function getLanguages()
|
||||
{
|
||||
return array(
|
||||
'en' => 'English',
|
||||
'ru' => 'Russian',
|
||||
'nl' => 'Dutch, Flemish',
|
||||
'de' => 'German',
|
||||
'it' => 'Italian',
|
||||
'fr' => 'French',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,11 +66,11 @@ class SetupController extends Controller
|
|||
$validate = new Validation();
|
||||
$user = new User();
|
||||
|
||||
/* set user as admin */
|
||||
# set user as admin
|
||||
$params['userrole'] = 'administrator';
|
||||
|
||||
/* get userroles for validation */
|
||||
$userroles = $user->getUserroles();
|
||||
# get userroles for validation
|
||||
$userroles = $this->c->acl->getRoles();
|
||||
|
||||
/* validate user */
|
||||
if($validate->newUser($params, $userroles))
|
||||
|
|
14
system/Events/OnResourcesLoaded.php
Normal file
14
system/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/Events/OnRolesPermissionsLoaded.php
Normal file
14
system/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/Events/OnSystemnaviLoaded.php
Normal file
14
system/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/Events/OnUserfieldsLoaded.php
Normal file
14
system/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
|
||||
{
|
||||
|
||||
}
|
|
@ -8,6 +8,7 @@ class TwigUserExtension extends \Twig_Extension
|
|||
{
|
||||
return [
|
||||
new \Twig_SimpleFunction('is_role', array($this, 'isRole' )),
|
||||
new \Twig_SimpleFunction('get_role', array($this, 'getRole' )),
|
||||
new \Twig_SimpleFunction('get_username', array($this, 'getUsername' ))
|
||||
];
|
||||
}
|
||||
|
@ -21,6 +22,15 @@ class TwigUserExtension extends \Twig_Extension
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getRole()
|
||||
{
|
||||
if(isset($_SESSION['role']))
|
||||
{
|
||||
return $_SESSION['role'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getUsername()
|
||||
{
|
||||
|
|
|
@ -8,6 +8,8 @@ use Slim\Http\Response;
|
|||
|
||||
class RedirectIfNoAdmin
|
||||
{
|
||||
# NOT IN USE ANYMORE
|
||||
/*
|
||||
protected $router;
|
||||
|
||||
public function __construct(RouterInterface $router, $flash)
|
||||
|
@ -29,4 +31,5 @@ class RedirectIfNoAdmin
|
|||
|
||||
return $next($request, $response);
|
||||
}
|
||||
*/
|
||||
}
|
37
system/Middleware/accessController.php
Normal file
37
system/Middleware/accessController.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Typemill\Middleware;
|
||||
|
||||
use Slim\Interfaces\RouterInterface;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
class accessController
|
||||
{
|
||||
protected $router;
|
||||
|
||||
public function __construct(RouterInterface $router, $acl, $resource, $privilege)
|
||||
{
|
||||
$this->router = $router;
|
||||
$this->acl = $acl;
|
||||
$this->resource = $resource;
|
||||
$this->privilege = $privilege;
|
||||
}
|
||||
|
||||
public function __invoke(Request $request, Response $response, $next)
|
||||
{
|
||||
if(!isset($_SESSION['login']))
|
||||
{
|
||||
return $response->withRedirect($this->router->pathFor('auth.show'));
|
||||
}
|
||||
|
||||
if(!$this->acl->isAllowed($_SESSION['role'], $this->resource, $this->privilege ))
|
||||
{
|
||||
# redirect to frontend startpage
|
||||
# alternatively return an error and show an error page.
|
||||
return $response->withRedirect($this->router->pathFor('home'));
|
||||
}
|
||||
|
||||
return $next($request, $response);
|
||||
}
|
||||
}
|
|
@ -78,7 +78,7 @@ class Fields
|
|||
}
|
||||
}
|
||||
elseif($field->getType() == "checkbox")
|
||||
{
|
||||
{
|
||||
# checkboxes need a special treatment, because field does not exist in settings if unchecked by user
|
||||
if(isset($userSettings[$objectType][$objectName][$fieldName]))
|
||||
{
|
||||
|
|
|
@ -29,6 +29,13 @@ class User extends WriteYaml
|
|||
$user = $this->getYaml('settings/users', $username . '.yaml');
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function getSecureUser($username)
|
||||
{
|
||||
$user = $this->getYaml('settings/users', $username . '.yaml');
|
||||
unset($user['password']);
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function createUser($params)
|
||||
{
|
||||
|
@ -59,25 +66,37 @@ class User extends WriteYaml
|
|||
{
|
||||
$userdata = $this->getUser($params['username']);
|
||||
|
||||
# make sure passwords are not overwritten
|
||||
if(isset($params['newpassword'])){ unset($params['newpassword']); }
|
||||
if(isset($params['password']))
|
||||
{
|
||||
$params['password'] = $this->generatePassword($params['password']);
|
||||
if(empty($params['password']))
|
||||
{
|
||||
unset($params['password']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$params['password'] = $this->generatePassword($params['password']);
|
||||
}
|
||||
}
|
||||
|
||||
$update = array_merge($userdata, $params);
|
||||
|
||||
$this->updateYaml('settings/users', $userdata['username'] . '.yaml', $update);
|
||||
|
||||
$_SESSION['user'] = $update['username'];
|
||||
$_SESSION['role'] = $update['userrole'];
|
||||
# if user updated his own profile, update session data
|
||||
if($_SESSION['user'] == $params['username'])
|
||||
{
|
||||
$_SESSION['role'] = $update['userrole'];
|
||||
|
||||
if(isset($update['firstname']))
|
||||
{
|
||||
$_SESSION['firstname'] = $update['firstname'];
|
||||
}
|
||||
if(isset($update['lastname']))
|
||||
{
|
||||
$_SESSION['lastname'] = $update['lastname'];
|
||||
if(isset($update['firstname']))
|
||||
{
|
||||
$_SESSION['firstname'] = $update['firstname'];
|
||||
}
|
||||
if(isset($update['lastname']))
|
||||
{
|
||||
$_SESSION['lastname'] = $update['lastname'];
|
||||
}
|
||||
}
|
||||
|
||||
return $userdata['username'];
|
||||
|
@ -91,11 +110,13 @@ class User extends WriteYaml
|
|||
}
|
||||
}
|
||||
|
||||
/* replaced by ACL
|
||||
public function getUserroles()
|
||||
{
|
||||
return array('administrator', 'editor');
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
public function login($username)
|
||||
{
|
||||
$user = $this->getUser($username);
|
||||
|
|
|
@ -52,11 +52,18 @@ class WriteMeta extends WriteYaml
|
|||
|
||||
$description = $this->generateDescription($content, $parsedown, $item);
|
||||
|
||||
# owner holds the edit-rights
|
||||
$owner = '';
|
||||
if(isset($_SESSION['user']))
|
||||
{
|
||||
$owner = $_SESSION['user'];
|
||||
}
|
||||
|
||||
$author = $settings['author'];
|
||||
|
||||
if(isset($_SESSION))
|
||||
{
|
||||
if(isset($_SESSION['firstname']) && $_SESSION['firstname'] !='' && isset($_SESSION['lastname']) && $_SESSION['lastname'] != '')
|
||||
if(isset($_SESSION['firstname']) && $_SESSION['firstname'] != '' && isset($_SESSION['lastname']) && $_SESSION['lastname'] != '')
|
||||
{
|
||||
$author = $_SESSION['firstname'] . ' ' . $_SESSION['lastname'];
|
||||
}
|
||||
|
@ -71,6 +78,7 @@ class WriteMeta extends WriteYaml
|
|||
'meta' => [
|
||||
'title' => $title,
|
||||
'description' => $description,
|
||||
'owner' => $owner,
|
||||
'author' => $author,
|
||||
'created' => date("Y-m-d"),
|
||||
'time' => date("H-i-s"),
|
||||
|
@ -88,6 +96,13 @@ class WriteMeta extends WriteYaml
|
|||
# used by MetaApiController. Do not set title or description in defaults if page is not published yet
|
||||
public function getPageMetaBlank($content, $settings, $item)
|
||||
{
|
||||
# owner holds the edit-rights
|
||||
$owner = '';
|
||||
if(isset($_SESSION['user']))
|
||||
{
|
||||
$owner = $_SESSION['user'];
|
||||
}
|
||||
|
||||
$author = $settings['author'];
|
||||
|
||||
if(isset($_SESSION))
|
||||
|
@ -107,6 +122,7 @@ class WriteMeta extends WriteYaml
|
|||
'meta' => [
|
||||
'title' => '',
|
||||
'description' => '',
|
||||
'owner' => $owner,
|
||||
'author' => $author,
|
||||
'created' => date("Y-m-d"),
|
||||
'time' => date("H-i-s"),
|
||||
|
|
|
@ -9,6 +9,7 @@ use Typemill\Controllers\ContentBackendController;
|
|||
use Typemill\Middleware\RedirectIfUnauthenticated;
|
||||
use Typemill\Middleware\RedirectIfAuthenticated;
|
||||
use Typemill\Middleware\RedirectIfNoAdmin;
|
||||
use Typemill\Middleware\accessController;
|
||||
|
||||
if($settings['settings']['setup'])
|
||||
{
|
||||
|
@ -35,37 +36,42 @@ $app->get('/tm/login', AuthController::class . ':show')->setName('auth.show')->a
|
|||
$app->post('/tm/login', AuthController::class . ':login')->setName('auth.login')->add(new RedirectIfAuthenticated($container['router'], $container['settings']));
|
||||
$app->get('/tm/logout', AuthController::class . ':logout')->setName('auth.logout')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
|
||||
$app->get('/tm/settings', SettingsController::class . ':showSettings')->setName('settings.show')->add(new RedirectIfNoAdmin($container['router'], $container['flash']));
|
||||
$app->post('/tm/settings', SettingsController::class . ':saveSettings')->setName('settings.save')->add(new RedirectIfNoAdmin($container['router'], $container['flash']));
|
||||
$app->get('/tm/themes', SettingsController::class . ':showThemes')->setName('themes.show')->add(new RedirectIfNoAdmin($container['router'], $container['flash']));
|
||||
$app->post('/tm/themes', SettingsController::class . ':saveThemes')->setName('themes.save')->add(new RedirectIfNoAdmin($container['router'], $container['flash']));
|
||||
$app->get('/tm/plugins', SettingsController::class . ':showPlugins')->setName('plugins.show')->add(new RedirectIfNoAdmin($container['router'], $container['flash']));
|
||||
$app->post('/tm/plugins', SettingsController::class . ':savePlugins')->setName('plugins.save')->add(new RedirectIfNoAdmin($container['router'], $container['flash']));
|
||||
$app->get('/tm/user/new', SettingsController::class . ':newUser')->setName('user.new')->add(new RedirectIfNoAdmin($container['router'], $container['flash']));
|
||||
$app->post('/tm/user/create', SettingsController::class . ':createUser')->setName('user.create')->add(new RedirectIfNoAdmin($container['router'], $container['flash']));
|
||||
$app->get('/tm/settings', SettingsController::class . ':showSettings')->setName('settings.show')->add(new accessController($container['router'], $container['acl'], 'system', 'view'));
|
||||
$app->post('/tm/settings', SettingsController::class . ':saveSettings')->setName('settings.save')->add(new accessController($container['router'], $container['acl'], 'system', 'update'));
|
||||
|
||||
$app->post('/tm/user/update', SettingsController::class . ':updateUser')->setName('user.update')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->post('/tm/user/delete', SettingsController::class . ':deleteUser')->setName('user.delete')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->get('/tm/user/{username}', SettingsController::class . ':showUser')->setName('user.show')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->get('/tm/user', SettingsController::class . ':listUser')->setName('user.list')->add(new RedirectIfNoAdmin($container['router'], $container['flash']));
|
||||
$app->get('/tm/themes', SettingsController::class . ':showThemes')->setName('themes.show')->add(new accessController($container['router'], $container['acl'], 'system', 'view'));
|
||||
$app->post('/tm/themes', SettingsController::class . ':saveThemes')->setName('themes.save')->add(new accessController($container['router'], $container['acl'], 'system', 'update'));
|
||||
|
||||
$app->get('/tm/content/raw[/{params:.*}]', ContentBackendController::class . ':showContent')->setName('content.raw')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->get('/tm/content/visual[/{params:.*}]', ContentBackendController::class . ':showBlox')->setName('content.visual')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->get('/tm/content[/{params:.*}]', ContentBackendController::class . ':showEmpty')->setName('content.empty')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->get('/tm/plugins', SettingsController::class . ':showPlugins')->setName('plugins.show')->add(new accessController($container['router'], $container['acl'], 'system', 'view'));
|
||||
$app->post('/tm/plugins', SettingsController::class . ':savePlugins')->setName('plugins.save')->add(new accessController($container['router'], $container['acl'], 'system', 'update'));
|
||||
|
||||
$app->get('/tm/account', SettingsController::class . ':showAccount')->setName('user.account')->add(new accessController($container['router'], $container['acl'], 'user', 'view'));
|
||||
$app->get('/tm/user/new', SettingsController::class . ':newUser')->setName('user.new')->add(new accessController($container['router'], $container['acl'], 'user', 'create'));
|
||||
$app->post('/tm/user/create', SettingsController::class . ':createUser')->setName('user.create')->add(new accessController($container['router'], $container['acl'], 'user', 'create'));
|
||||
$app->post('/tm/user/update', SettingsController::class . ':updateUser')->setName('user.update')->add(new accessController($container['router'], $container['acl'], 'user', 'update'));
|
||||
$app->post('/tm/user/delete', SettingsController::class . ':deleteUser')->setName('user.delete')->add(new accessController($container['router'], $container['acl'], 'user', 'delete'));
|
||||
$app->get('/tm/user/{username}', SettingsController::class . ':showUser')->setName('user.show')->add(new accessController($container['router'], $container['acl'], 'user', 'view'));
|
||||
$app->get('/tm/users', SettingsController::class . ':listUser')->setName('user.list')->add(new accessController($container['router'], $container['acl'], 'userlist', 'view'));
|
||||
|
||||
$app->get('/tm/content/raw[/{params:.*}]', ContentBackendController::class . ':showContent')->setName('content.raw')->add(new accessController($container['router'], $container['acl'], 'content', 'view'));
|
||||
$app->get('/tm/content/visual[/{params:.*}]', ContentBackendController::class . ':showBlox')->setName('content.visual')->add(new accessController($container['router'], $container['acl'], 'content', 'view'));
|
||||
$app->get('/tm/content[/{params:.*}]', ContentBackendController::class . ':showEmpty')->setName('content.empty')->add(new accessController($container['router'], $container['acl'], 'content', 'view'));
|
||||
|
||||
foreach($routes as $pluginRoute)
|
||||
{
|
||||
$method = $pluginRoute['httpMethod'];
|
||||
$route = $pluginRoute['route'];
|
||||
$class = $pluginRoute['class'];
|
||||
$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']);
|
||||
$app->{$method}($route, $class)->setName($pluginRoute['name'])->add(new accessController($container['router'], $container['acl'], $resource, $privilege));
|
||||
}
|
||||
else
|
||||
{
|
||||
$app->{$method}($route, $class);
|
||||
$app->{$method}($route, $class)->add(new accessController($container['router'], $container['acl'], $resource, $privilege));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
namespace Typemill;
|
||||
|
||||
use Laminas\Permissions\Acl\Acl;
|
||||
use Laminas\Permissions\Acl\Role\GenericRole as Role;
|
||||
use Laminas\Permissions\Acl\Resource\GenericResource as Resource;
|
||||
|
||||
class Settings
|
||||
{
|
||||
public static function loadSettings()
|
||||
|
@ -182,4 +186,59 @@ class Settings
|
|||
$yaml->updateYaml('settings', 'settings.yaml', $settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function loadResources()
|
||||
{
|
||||
return ['content',
|
||||
'mycontent',
|
||||
'user',
|
||||
'userlist',
|
||||
'system'];
|
||||
}
|
||||
|
||||
public static function loadRolesAndPermissions()
|
||||
{
|
||||
$member['name'] = 'member';
|
||||
$member['inherits'] = NULL;
|
||||
$member['permissions'] = ['user' => ['view','update','delete']];
|
||||
|
||||
$author['name'] = 'author';
|
||||
$author['inherits'] = 'member';
|
||||
$author['permissions'] = ['mycontent' => ['view', 'create', 'update'],
|
||||
'content' => ['view']];
|
||||
|
||||
$editor['name'] = 'editor';
|
||||
$editor['inherits'] = 'author';
|
||||
$editor['permissions'] = [ 'mycontent' => ['delete', 'publish', 'unpublish'],
|
||||
'content' => ['create', 'update', 'delete', 'publish', 'unpublish']];
|
||||
|
||||
return [$member, $author, $editor];
|
||||
}
|
||||
|
||||
public static function createAcl($roles, $resources)
|
||||
{
|
||||
$acl = new Acl();
|
||||
|
||||
foreach($resources as $resource)
|
||||
{
|
||||
$acl->addResource(new Resource($resource));
|
||||
}
|
||||
|
||||
# add administrator role
|
||||
$acl->addRole(new Role('administrator'));
|
||||
$acl->allow('administrator');
|
||||
|
||||
# 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);
|
||||
}
|
||||
}
|
||||
|
||||
return $acl;
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ class Translations
|
|||
$yaml = new Models\WriteYaml();
|
||||
$settings = $yaml->getYaml('settings', 'settings.yaml');
|
||||
|
||||
if($settings === FALSE){
|
||||
if(!isset($settings['language'])){
|
||||
$language = \Typemill\Settings::whichLanguage();
|
||||
} else {
|
||||
$language = $settings['language'];
|
||||
|
|
|
@ -67,9 +67,12 @@ a, a:link, a:visited, a:focus, a:hover, a:active, .link, button, .button, .tab-b
|
|||
.hover-bg-tm-green:hover{
|
||||
background:#66b0a3;
|
||||
}
|
||||
.hover-b--tm-green:hover{
|
||||
.hover-b--tm-green:hover,.hover-b--tm-green.active{
|
||||
border-color:#66b0a3;
|
||||
}
|
||||
.hover-bg-white.active{
|
||||
background-color: #fff;
|
||||
}
|
||||
.w-100{
|
||||
width:100%!important;
|
||||
}
|
||||
|
@ -717,6 +720,9 @@ li.row{
|
|||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
li.row.header{
|
||||
display:none;
|
||||
}
|
||||
li.row ul{
|
||||
background: #f9f8f6;
|
||||
margin: 5px 0;
|
||||
|
@ -735,6 +741,15 @@ li.col.username, li.col.email, li.col.userrole, li.col.edit{
|
|||
li.col.username{
|
||||
border-top: 2px solid #70c1b3;
|
||||
}
|
||||
li.col:before{
|
||||
width: 25%;
|
||||
font-weight:900;
|
||||
display:inline-block;
|
||||
}
|
||||
li.col.username:before{content:"User: ";}
|
||||
li.col.userrole:before{content:"Role: ";}
|
||||
li.col.email:before{content:"Mail: ";}
|
||||
li.col.edit:before{content:"Link: ";}
|
||||
.col.username,.col.email,.col.userrole, .col.edit{
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -2778,6 +2793,23 @@ footer a:focus, footer a:hover, footer a:active
|
|||
margin-top: 10px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
li.row.header{
|
||||
display: block;
|
||||
}
|
||||
li.row.header ul{
|
||||
color: #fff;
|
||||
background: #70c1b3;
|
||||
}
|
||||
li.col.username, li.col.email, li.col.userrole, li.col.edit{
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
li.col.username{
|
||||
border-top: 2px solid #70c1b3;
|
||||
}
|
||||
li.col:before{
|
||||
width: 0%;
|
||||
display:none;
|
||||
}
|
||||
li.row ul{
|
||||
margin: 0px;
|
||||
}
|
||||
|
@ -2786,10 +2818,10 @@ footer a:focus, footer a:hover, footer a:active
|
|||
}
|
||||
.col.edit{
|
||||
width: 10%;
|
||||
}
|
||||
}
|
||||
li.col.username{
|
||||
border-top: 0px;
|
||||
border-left: 2px solid #70c1b3;
|
||||
border-left: 0px solid #70c1b3;
|
||||
}
|
||||
.buttonset{
|
||||
width: 76%;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
<div class="formWrapper">
|
||||
|
||||
{% if (acl.isAllowed(get_role(), 'content', 'update')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'update')) ) %}
|
||||
|
||||
<div id="metanav" class="metanav" v-cloak>
|
||||
|
||||
<button
|
||||
|
@ -26,6 +28,8 @@
|
|||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
<section id="blox" :class="showBlox">
|
||||
|
||||
<div class="blox-body">
|
||||
|
@ -60,17 +64,21 @@
|
|||
</content-block>
|
||||
</draggable>
|
||||
</div>
|
||||
|
||||
<div class="format-bar">
|
||||
|
||||
<content-block :body="false">
|
||||
{% if (acl.isAllowed(get_role(), 'content', 'edit')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'update')) ) %}
|
||||
|
||||
<button v-for="button in formats" class="format-item" @click.prevent="setData( $event, button.component )" data-id="99999" id="blox-99999" :title="button.title|translate" v-html="button.label"></button>
|
||||
|
||||
</content-block>
|
||||
<div class="format-bar">
|
||||
|
||||
<content-block :body="false">
|
||||
|
||||
<button v-for="button in formats" class="format-item" @click.prevent="setData( $event, button.component )" data-id="99999" id="blox-99999" :title="button.title|translate" v-html="button.label"></button>
|
||||
|
||||
</content-block>
|
||||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
<div class="formWrapper">
|
||||
|
||||
{% if (acl.isAllowed(get_role(), 'content', 'update')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'update')) ) %}
|
||||
|
||||
<div id="metanav" class="metanav" v-cloak>
|
||||
|
||||
<button
|
||||
|
@ -26,6 +28,8 @@
|
|||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
<div id="editor" class="editor">
|
||||
<form action="#" v-cloak>
|
||||
|
||||
|
|
|
@ -2,30 +2,47 @@
|
|||
|
||||
<div class="editor buttonset" id="publishController" data-published="{{ item.published }}" data-drafted="{{ item.drafted }}" v-cloak>
|
||||
<div v-if="errors.message" class="message error">${ errors.message }</div>
|
||||
<button v-if="raw" @click.prevent="saveDraft" id="draft" :class="draftResult" :disabled="draftDisabled"><span class="desktop">{{ __('Save') }} </span>{{ __('Draft') }}</button><button @click.prevent="publishDraft" id="publish" :class="publishResult" :disabled="publishDisabled">{{ __('Publish') }}</button>
|
||||
<button @click.prevent="showModal('discard')" v-if="visual && !publishStatus" id="discard" :class="discardResult" :disabled="publishDisabled">{{ __('Discard') }}</button>
|
||||
{% if (acl.isAllowed(get_role(), 'content', 'update')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'update')) ) %}
|
||||
<button v-if="raw" @click.prevent="saveDraft" id="draft" :class="draftResult" :disabled="draftDisabled"><span class="desktop">{{ __('Save') }} </span>{{ __('Draft') }}</button>
|
||||
{% endif %}
|
||||
{% if (acl.isAllowed(get_role(), 'content', 'publish')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'publish')) ) %}
|
||||
<button @click.prevent="publishDraft" id="publish" :class="publishResult" :disabled="publishDisabled">{{ __('Publish') }}</button>
|
||||
{% endif %}
|
||||
{% if (acl.isAllowed(get_role(), 'content', 'update')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'update')) ) %}
|
||||
<button @click.prevent="showModal('discard')" v-if="visual && !publishStatus" id="discard" :class="discardResult" :disabled="publishDisabled">{{ __('Discard') }}</button>
|
||||
{% endif %}
|
||||
<div class="secondary">
|
||||
<button @click.prevent="depublishArticle" class="button--secondary" :disabled="publishStatus"><span class="desktop">${publishLabel}</span><span class="mobile">${publishLabelMobile}</span></button>
|
||||
<button @click.prevent="showModal('delete')" class="button--secondary danger"><span class="desktop">{{ __('delete') }}</span><span class="mobile">X</span></button>
|
||||
<a v-if="visual" href="{{ base_url }}/tm/content/raw{{ itemurl }}" class="button--secondary"><span class="desktop">{{ __('raw mode') }}</span><span class="mobile">{{ __('raw') }}</span></a>
|
||||
<a v-if="raw" href="{{ base_url }}/tm/content/visual{{ itemurl }}" class="button--secondary"><span class="desktop">{{ __('visual mode') }}</span><span class="mobile">{{ __('visual') }}</span></a>
|
||||
{% if (acl.isAllowed(get_role(), 'content', 'unpublish')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'unpublish')) ) %}
|
||||
<button @click.prevent="depublishArticle" class="button--secondary" :disabled="publishStatus"><span class="desktop">${publishLabel}</span><span class="mobile">${publishLabelMobile}</span></button>
|
||||
{% endif %}
|
||||
{% if (acl.isAllowed(get_role(), 'content', 'delete')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'delete')) ) %}
|
||||
<button @click.prevent="showModal('delete')" class="button--secondary danger"><span class="desktop">{{ __('delete') }}</span><span class="mobile">X</span></button>
|
||||
{% endif %}
|
||||
{% if (acl.isAllowed(get_role(), 'content', 'update')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'update')) ) %}
|
||||
<a v-if="visual" href="{{ base_url }}/tm/content/raw{{ itemurl }}" class="button--secondary"><span class="desktop">{{ __('raw mode') }}</span><span class="mobile">{{ __('raw') }}</span></a>
|
||||
<a v-if="raw" href="{{ base_url }}/tm/content/visual{{ itemurl }}" class="button--secondary"><span class="desktop">{{ __('visual mode') }}</span><span class="mobile">{{ __('visual') }}</span></a>
|
||||
{% endif %}
|
||||
<a target="_blank" class="button--secondary" href="{{ item.urlAbs }}"><svg class="icon baseline icon-external-link"><use xlink:href="#icon-external-link"></use></svg></a>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<div v-if="modalWindow" id="modalWindow" class="modalWindow">
|
||||
<div class="modalInner">
|
||||
<div @click="hideModal" id="closeModal" class="closeModal">X</div>
|
||||
<div v-if="modalType == 'delete'">
|
||||
<h2>{{ __('Delete page') }}</h2>
|
||||
<p>{{ __('Do you really want to delete this page') }} {{ __('Please confirm') }}</p>
|
||||
<button @click.prevent="deleteArticle" class="large alert" :class="deleteResult" :disabled="deleteDisabled">{{ __('Delete Page') }}</button>
|
||||
</div>
|
||||
<div v-if="modalType == 'discard'">
|
||||
<h2>{{ __('Discard Changes') }}</h2>
|
||||
<p>{{ __('Do you want to discard your changes and set the content back to the live version') }}</p>
|
||||
<button @click.prevent="discardDraft" class="large fullwidth" :class="discardResult" :disabled="publishDisabled">{{ __('Discard Changes') }}</button>
|
||||
<transition name="fade">
|
||||
<div v-if="modalWindow" id="modalWindow" class="modalWindow">
|
||||
<div class="modalInner">
|
||||
<div @click="hideModal" id="closeModal" class="closeModal">X</div>
|
||||
{% if (acl.isAllowed(get_role(), 'content', 'delete')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'delete')) ) %}
|
||||
<div v-if="modalType == 'delete'">
|
||||
<h2>{{ __('Delete page') }}</h2>
|
||||
<p>{{ __('Do you really want to delete this page') }} {{ __('Please confirm') }}</p>
|
||||
<button @click.prevent="deleteArticle" class="large alert" :class="deleteResult" :disabled="deleteDisabled">{{ __('Delete Page') }}</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if (acl.isAllowed(get_role(), 'content', 'update')) or ( (mycontent) and (acl.isAllowed(get_role(), 'mycontent', 'update')) ) %}
|
||||
<div v-if="modalType == 'discard'">
|
||||
<h2>{{ __('Discard Changes') }}</h2>
|
||||
<p>{{ __('Do you want to discard your changes and set the content back to the live version') }}</p>
|
||||
<button @click.prevent="discardDraft" class="large fullwidth" :class="discardResult" :disabled="publishDisabled">{{ __('Discard Changes') }}</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</transition>
|
||||
</div>
|
|
@ -401,6 +401,7 @@ const contentComponent = Vue.component('content-block', {
|
|||
if(httpStatus == 400)
|
||||
{
|
||||
self.activatePage();
|
||||
publishController.errors.message = "Looks like you are logged out. Please login and try again.";
|
||||
}
|
||||
if(response)
|
||||
{
|
||||
|
@ -410,7 +411,7 @@ const contentComponent = Vue.component('content-block', {
|
|||
|
||||
if(result.errors)
|
||||
{
|
||||
publishController.errors.message = result.errors;
|
||||
publishController.errors.message = result.errors.message;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1587,6 +1588,7 @@ const imageComponent = Vue.component('image-component', {
|
|||
if(httpStatus == 400)
|
||||
{
|
||||
self.activatePage();
|
||||
publishController.errors.message = "Looks like you are logged out. Please login and try again.";
|
||||
}
|
||||
if(response)
|
||||
{
|
||||
|
@ -1777,6 +1779,7 @@ const fileComponent = Vue.component('file-component', {
|
|||
if(httpStatus == 400)
|
||||
{
|
||||
self.activatePage();
|
||||
publishController.errors.message = "Looks like you are logged out. Please login and try again.";
|
||||
}
|
||||
if(response)
|
||||
{
|
||||
|
@ -2316,6 +2319,7 @@ let editor = new Vue({
|
|||
el: '#blox',
|
||||
/* components: componentList, */
|
||||
data: {
|
||||
errors: [],
|
||||
root: document.getElementById("main").dataset.url,
|
||||
html: false,
|
||||
title: false,
|
||||
|
|
|
@ -516,6 +516,10 @@ let meta = new Vue({
|
|||
{
|
||||
self.formErrors = error.response.data.errors;
|
||||
}
|
||||
if(error.response.data.errors.message)
|
||||
{
|
||||
publishController.errors.message = error.response.data.errors.message;
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ let publishController = new Vue({
|
|||
self.publishDisabled = false;
|
||||
self.publishResult = "fail";
|
||||
self.errors.message = "Something went wrong, please refresh the page and try again."
|
||||
}
|
||||
}
|
||||
}, method, url, this.form );
|
||||
},
|
||||
discardDraft: function(e) {
|
||||
|
@ -118,7 +118,6 @@ let publishController = new Vue({
|
|||
{
|
||||
self.publishDisabled = false;
|
||||
self.discardResult = "fail";
|
||||
|
||||
if(result.errors.title){ editor.errors.title = result.errors.title[0] }
|
||||
if(result.errors.content){ editor.errors.content = result.errors.content[0] }
|
||||
if(result.errors.message){ self.errors.message = result.errors.message }
|
||||
|
@ -212,12 +211,6 @@ let publishController = new Vue({
|
|||
self.publishResult = "fail";
|
||||
self.errors.message = "You are probably logged out. Please backup your changes, login and then try again."
|
||||
}
|
||||
else if(httpStatus != 200)
|
||||
{
|
||||
self.publishDisabled = false;
|
||||
self.publishResult = "fail";
|
||||
self.errors.message = "Something went wrong, please refresh the page and try again."
|
||||
}
|
||||
else if(response)
|
||||
{
|
||||
var result = JSON.parse(response);
|
||||
|
@ -236,6 +229,12 @@ let publishController = new Vue({
|
|||
navi.getNavi();
|
||||
}
|
||||
}
|
||||
else if(httpStatus != 200)
|
||||
{
|
||||
self.publishDisabled = false;
|
||||
self.publishResult = "fail";
|
||||
self.errors.message = "Something went wrong, please refresh the page and try again.";
|
||||
}
|
||||
}, method, url, this.form );
|
||||
},
|
||||
deleteArticle: function(e){
|
||||
|
|
|
@ -41,6 +41,22 @@
|
|||
<title>power-off</title>
|
||||
<path d="M24 14c0 6.609-5.391 12-12 12s-12-5.391-12-12c0-3.797 1.75-7.297 4.797-9.578 0.891-0.672 2.141-0.5 2.797 0.391 0.672 0.875 0.484 2.141-0.391 2.797-2.031 1.531-3.203 3.859-3.203 6.391 0 4.406 3.594 8 8 8s8-3.594 8-8c0-2.531-1.172-4.859-3.203-6.391-0.875-0.656-1.062-1.922-0.391-2.797 0.656-0.891 1.922-1.062 2.797-0.391 3.047 2.281 4.797 5.781 4.797 9.578zM14 2v10c0 1.094-0.906 2-2 2s-2-0.906-2-2v-10c0-1.094 0.906-2 2-2s2 0.906 2 2z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-user" viewBox="0 0 20 28">
|
||||
<path d="M20 21.859c0 2.281-1.5 4.141-3.328 4.141h-13.344c-1.828 0-3.328-1.859-3.328-4.141 0-4.109 1.016-8.859 5.109-8.859 1.266 1.234 2.984 2 4.891 2s3.625-0.766 4.891-2c4.094 0 5.109 4.75 5.109 8.859zM16 8c0 3.313-2.688 6-6 6s-6-2.688-6-6 2.688-6 6-6 6 2.688 6 6z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-group" viewBox="0 0 30 28">
|
||||
<path d="M9.266 14c-1.625 0.047-3.094 0.75-4.141 2h-2.094c-1.563 0-3.031-0.75-3.031-2.484 0-1.266-0.047-5.516 1.937-5.516 0.328 0 1.953 1.328 4.062 1.328 0.719 0 1.406-0.125 2.078-0.359-0.047 0.344-0.078 0.688-0.078 1.031 0 1.422 0.453 2.828 1.266 4zM26 23.953c0 2.531-1.672 4.047-4.172 4.047h-13.656c-2.5 0-4.172-1.516-4.172-4.047 0-3.531 0.828-8.953 5.406-8.953 0.531 0 2.469 2.172 5.594 2.172s5.063-2.172 5.594-2.172c4.578 0 5.406 5.422 5.406 8.953zM10 4c0 2.203-1.797 4-4 4s-4-1.797-4-4 1.797-4 4-4 4 1.797 4 4zM21 10c0 3.313-2.688 6-6 6s-6-2.688-6-6 2.688-6 6-6 6 2.688 6 6zM30 13.516c0 1.734-1.469 2.484-3.031 2.484h-2.094c-1.047-1.25-2.516-1.953-4.141-2 0.812-1.172 1.266-2.578 1.266-4 0-0.344-0.031-0.688-0.078-1.031 0.672 0.234 1.359 0.359 2.078 0.359 2.109 0 3.734-1.328 4.062-1.328 1.984 0 1.937 4.25 1.937 5.516zM28 4c0 2.203-1.797 4-4 4s-4-1.797-4-4 1.797-4 4-4 4 1.797 4 4z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-wrench" viewBox="0 0 26 28">
|
||||
<path d="M6 23c0-0.547-0.453-1-1-1s-1 0.453-1 1 0.453 1 1 1 1-0.453 1-1zM16.063 16.438l-10.656 10.656c-0.359 0.359-0.875 0.578-1.406 0.578s-1.047-0.219-1.422-0.578l-1.656-1.687c-0.375-0.359-0.594-0.875-0.594-1.406s0.219-1.047 0.594-1.422l10.641-10.641c0.812 2.047 2.453 3.687 4.5 4.5zM25.969 9.641c0 0.516-0.187 1.156-0.359 1.656-0.984 2.781-3.656 4.703-6.609 4.703-3.859 0-7-3.141-7-7s3.141-7 7-7c1.141 0 2.625 0.344 3.578 0.984 0.156 0.109 0.25 0.25 0.25 0.438 0 0.172-0.109 0.344-0.25 0.438l-4.578 2.641v3.5l3.016 1.672c0.516-0.297 4.141-2.578 4.453-2.578s0.5 0.234 0.5 0.547z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-plug" viewBox="0 0 28 28">
|
||||
<path d="M27.422 7.078c0.766 0.781 0.766 2.047 0 2.828l-6.266 6.25 2.344 2.344-2.5 2.5c-3.422 3.422-8.641 3.906-12.516 1.344l-5.656 5.656h-2.828v-2.828l5.656-5.656c-2.562-3.875-2.078-9.094 1.344-12.516l2.5-2.5 2.344 2.344 6.25-6.266c0.781-0.766 2.047-0.766 2.828 0 0.781 0.781 0.781 2.063 0 2.828l-6.25 6.266 3.656 3.656 6.266-6.25c0.781-0.781 2.047-0.781 2.828 0z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-paint-brush" viewBox="0 0 28 28">
|
||||
<path d="M25.234 0c1.422 0 2.734 1.062 2.734 2.547 0 0.828-0.328 1.625-0.703 2.359-1.219 2.312-5.313 9.953-7.266 11.75-0.953 0.891-2.078 1.422-3.406 1.422-2.641 0-4.797-2.25-4.797-4.875 0-1.25 0.516-2.469 1.437-3.313l9.969-9.047c0.547-0.5 1.266-0.844 2.031-0.844zM11.031 16.156c0.812 1.578 2.297 2.766 4.016 3.219l0.016 1.109c0.094 4.453-3 7.516-7.469 7.516-5.297 0-7.594-4.219-7.594-9.016 0.578 0.391 2.594 2 3.25 2 0.391 0 0.719-0.219 0.859-0.578 1.328-3.469 3.406-4.094 6.922-4.25z"></path>
|
||||
</symbol>
|
||||
{{ assets.renderSvg() }}
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
|
|
@ -18,11 +18,16 @@ meta:
|
|||
heroimagealt:
|
||||
type: text
|
||||
label: Alternative Text for the hero image
|
||||
owner:
|
||||
type: text
|
||||
label: owner (username)
|
||||
class: medium
|
||||
description: Has edit rights for this article.
|
||||
author:
|
||||
type: text
|
||||
label: author
|
||||
class: large
|
||||
description: Taken from your user account if set.
|
||||
class: medium
|
||||
description: Can be used for author line in frontend.
|
||||
manualdate:
|
||||
type: date
|
||||
label: Manual date
|
||||
|
|
|
@ -1,19 +1,12 @@
|
|||
<nav id="sidebar-menu" class="sidebar-menu">
|
||||
{% if is_role('administrator') %}
|
||||
<div id="mobile-menu" class="menu-action">{{ __('Menu') }} <span class="button-arrow"></span></div>
|
||||
<h3>{{ __('Settings') }}</h3>
|
||||
<ul class="menu-list margin-bottom">
|
||||
<li class="menu-item"><a href="{{ path_for('settings.show') }}"{{ (route == 'settings.show') ? ' class="active"' : '' }}>{{ __('System') }}</a></li>
|
||||
<li class="menu-item"><a href="{{ path_for('themes.show') }}"{{ (route == 'themes.show') ? ' class="active"' : '' }}>{{ __('Themes') }}</a></li>
|
||||
<li class="menu-item"><a href="{{ path_for('plugins.show') }}"{{ (route == 'plugins.show') ? ' class="active"' : '' }}>{{ __('Plugins') }}</a></li>
|
||||
</ul>
|
||||
<h3>{{ __('Users') }}</h3>
|
||||
<ul class="menu-list">
|
||||
<li class="menu-item"><a href="{{ path_for('user.list') }}"{{ (route == 'user.list') ? ' class="active"' : '' }}>{{ __('All users') }}</a></li>
|
||||
<li class="menu-item"><a href="{{ path_for('user.new') }}"{{ (route == 'user.new') ? ' class="active"' : '' }}>{{ __('Create user') }}</a></li>
|
||||
{% for user in users %}
|
||||
<li class="menu-item"><a href="{{ path_for('user.show', {'username' : user }) }}"{{ (username == user) ? ' class="active"' : '' }}>{{ user }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
<div id="mobile-menu" class="menu-action">{{ __('Menu') }} <span class="button-arrow"></span></div>
|
||||
<ul class="list pa0 ma0">
|
||||
|
||||
{% for name,navitem in navigation %}
|
||||
{% if acl.isAllowed(get_role(), navitem.aclresource, navitem.aclprivilege) %}
|
||||
<li class="pb1"><a class="link dark-gray hover-bg-white bl bw2 b--near-white hover-b--tm-green pa2 dib w-100{{ navitem.active ? ' active' : '' }}" href="{{ path_for(navitem.routename) }}"><svg class="icon baseline {{ navitem.icon }} mr2"><use xlink:href="#{{ navitem.icon }}"></use></svg> {{ __(name) }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
</ul>
|
||||
</nav>
|
|
@ -1,5 +1,5 @@
|
|||
<div class="cardField{{ errors[itemName][field.name] ? ' error' : '' }}{{field.fieldsize ? ' ' ~ field.fieldsize : ''}}">
|
||||
|
||||
<div class="{{ class ? class : 'cardField' }}{{ errors[itemName][field.name] ? ' error' : '' }}{{field.fieldsize ? ' ' ~ field.fieldsize : ''}}">
|
||||
|
||||
<label for="{{ itemName }}[{{ field.name }}]">{{ __( field.getLabel() ) }}
|
||||
{% if field.getAttribute('required') %}<strong><abbr title="{{ __('required') }}">*</abbr></strong>{% endif %}
|
||||
{% if field.help %}<div class="help">?<span class="tooltip">{{__(field.help|slice(0,100))}}</span></div>{% endif %}
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
{% set content = (current_url matches '/content.*/') ? true : false %}
|
||||
|
||||
<nav class="header-navi">
|
||||
<div class="logo">
|
||||
<a href="{{ base_url }}/tm/content/{{ settings.editor }}">Typemill</a>
|
||||
</div>
|
||||
<ul class="navi-items">
|
||||
<li><a href="{{ base_url }}/tm/content/{{ settings.editor }}"{{ navigation ? ' class="active"' : '' }}><svg class="icon baseline icon-file-text-o"><use xlink:href="#icon-file-text-o"></use></svg><span class="nav-label"> {{ __('Content') }}</span></a></li><li>
|
||||
{% if is_role('administrator') %}
|
||||
<a href="{{ path_for('settings.show') }}"{{ users ? ' class="active"' : '' }}><svg class="icon baseline icon-cog"><use xlink:href="#icon-cog"></use></svg><span class="nav-label"> {{ __('Settings') }}</span></a></li><li>
|
||||
<li>
|
||||
{% if acl.isAllowed(get_role(), 'content', 'view') %}
|
||||
<a href="{{ base_url }}/tm/content/{{ settings.editor }}"{{ content ? ' class="active"' : '' }}><svg class="icon baseline icon-file-text-o"><use xlink:href="#icon-file-text-o"></use></svg><span class="nav-label"> {{ __('Content') }}</span></a></li><li>
|
||||
{% endif %}
|
||||
{% if acl.isAllowed(get_role(), 'system', 'view') %}
|
||||
<a href="{{ path_for('settings.show') }}"{{ content ? '' : 'class="active"' }}><svg class="icon baseline icon-cog"><use xlink:href="#icon-cog"></use></svg><span class="nav-label"> {{ __('Settings') }}</span></a></li><li>
|
||||
{% else %}
|
||||
<a href="{{ path_for('user.show', {'username' : get_username() }) }}"{{ users ? ' class="active"' : '' }}><svg class="icon icon-cog baseline"><use xlink:href="#icon-cog, gear"></use></svg><span class="nav-label"> {{ __('Account') }}</span></a></li><li>
|
||||
<a href="{{ path_for('user.account') }}"{{ content ? '' : 'class="active"' }}><svg class="icon icon-cog baseline"><use xlink:href="#icon-cog"></use></svg><span class="nav-label"> {{ __('Settings') }}</span></a></li><li>
|
||||
{% endif %}
|
||||
<a href="{{ base_url }}"><svg class="icon baseline icon-external-link"><use xlink:href="#icon-external-link"></use></svg><span class="nav-label"> {{ __('View Site') }}</span></a></li><li>
|
||||
<a href="{{ path_for('auth.logout') }}"><svg class="icon baseline icon-power-off"><use xlink:href="#icon-power-off"></use></svg><span class="nav-label"> {{ __('Logout') }}</span></a></li>
|
||||
|
|
|
@ -5,79 +5,35 @@
|
|||
|
||||
<div class="formWrapper">
|
||||
|
||||
<form id="userform" method="POST" action="{{ path_for('user.update') }}">
|
||||
<form id="userform" method="POST" action="{{ path_for('user.update') }}" enctype="multipart/form-data">
|
||||
|
||||
<section id="user" class="settings">
|
||||
|
||||
<header class="headline">
|
||||
<h1>{{ __('Edit User') }}</h1>
|
||||
<h1>{{ userdata.username }}</h1>
|
||||
</header>
|
||||
|
||||
<fieldset class="auth">
|
||||
|
||||
<div class="large{{ errors.username ? ' errors' : '' }}">
|
||||
<label for="username">{{ __('Username') }} <small>({{ __('not editable') }})</small></label>
|
||||
<input type="text" name="showusername" value="{{ old.username ? old.username : userdata.username }}" required disabled>
|
||||
<input type="hidden" name="username" value="{{ userdata.username }}">
|
||||
{% if errors.username %}
|
||||
<span class="error">{{ errors.username | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="large{{ errors.firstname ? ' errors' : '' }}">
|
||||
<label for="firstname">{{ __('First Name') }}</label>
|
||||
<input type="text" name="firstname" value="{{ old.firstname ? old.firstname : userdata.firstname }}">
|
||||
{% if errors.firstname %}
|
||||
<span class="error">{{ errors.firstname | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% for field in userform %}
|
||||
|
||||
<div class="large{{ errors.lastname ? ' errors' : '' }}">
|
||||
<label for="lastname">{{ __('Last Name') }}</label>
|
||||
<input type="text" name="lastname" value="{{ old.lastname ? old.lastname : userdata.lastname }}">
|
||||
{% if errors.lastname %}
|
||||
<span class="error">{{ errors.lastname | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="large{{ errors.email ? ' errors' : '' }}">
|
||||
<label for="email">{{ __('E-Mail') }} <abbr title="{{ __('required') }}">*</abbr></label>
|
||||
<input type="text" name="email" value="{{ old.email ? old.email : userdata.email }}" required>
|
||||
{% if errors.email %}
|
||||
<span class="error">{{ errors.email | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if is_role('administrator') %}
|
||||
<div class="large{{ errors.userrole ? ' errors' : '' }}">
|
||||
<label for="userrole">{{ __('Role') }} <abbr title="{{ __('required') }}">*</abbr></label>
|
||||
<select name="userrole" required>
|
||||
{% for role in userrole %}
|
||||
<option value="{{ role }}"{% if (role == old.userrole or role == userdata.userrole) %} selected{% endif %}>{{ role }}</option>
|
||||
{% if field.type == 'fieldset' %}
|
||||
|
||||
<fieldset class="subfield">
|
||||
<legend>{{ field.legend }}</legend>
|
||||
{% for field in field.fields %}
|
||||
{% include '/partials/fields.twig' with { 'settings': usersettings, 'object' : 'users', 'itemName' : 'user', 'class' : 'large' } %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% if errors.userrole %}
|
||||
<span class="error">{{ errors.userrole | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="large{{ errors.password ? ' errors' : '' }}">
|
||||
<label for="password">{{ __('Actual Password') }}</label>
|
||||
<input type="password" name="password">
|
||||
{% if errors.password %}
|
||||
<span class="error">{{ errors.password | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{% else %}
|
||||
|
||||
{% include '/partials/fields.twig' with { 'settings': usersettings, 'object' : 'users', 'itemName' : 'user', 'class' : 'large' } %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
<div class="large{{ errors.newpassword ? ' errors' : '' }}">
|
||||
<label for="newpassword">{{ __('New Password') }}</label>
|
||||
<input type="password" name="newpassword">
|
||||
{% if errors.newpassword %}
|
||||
<span class="error">{{ errors.newpassword | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
||||
</section>
|
||||
|
@ -87,7 +43,7 @@
|
|||
<div class="actionLink">
|
||||
<a href="#" id="openModal" class="openModal">{{ __('Delete User') }}</a>
|
||||
</div>
|
||||
</form>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="modalWindow" class="modal">
|
||||
|
@ -103,5 +59,4 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -12,6 +12,14 @@
|
|||
</header>
|
||||
|
||||
<ul class="userlist">
|
||||
<li class="row header">
|
||||
<ul>
|
||||
<li class="col username">Username
|
||||
</li><li class="col userrole">Role
|
||||
</li><li class="col email">E-Mail
|
||||
</li><li class="col edit">Edit</li>
|
||||
</ul>
|
||||
</li>
|
||||
{% for user in userdata %}
|
||||
|
||||
<li class="row">
|
||||
|
|
|
@ -23,30 +23,6 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="large{{ errors.firstname ? ' errors' : '' }}">
|
||||
<label for="firstname">{{ __('First Name') }}</label>
|
||||
<input type="text" name="firstname" value="{{ old.firstname ? old.firstname : userdata.firstname }}">
|
||||
{% if errors.firstname %}
|
||||
<span class="error">{{ errors.firstname | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="large{{ errors.lastname ? ' errors' : '' }}">
|
||||
<label for="lastname">{{ __('Last Name') }}</label>
|
||||
<input type="text" name="lastname" value="{{ old.lastname ? old.lastname : userdata.lastname }}">
|
||||
{% if errors.lastname %}
|
||||
<span class="error">{{ errors.lastname | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="large{{ errors.email ? ' errors' : '' }}">
|
||||
<label for="email">{{ __('E-Mail') }} <abbr title="{{ __('required') }}">*</abbr></label>
|
||||
<input type="text" name="email" value="{{ old.email ? old.email : '' }}" required>
|
||||
{% if errors.email %}
|
||||
<span class="error">{{ errors.email | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="large{{ errors.userrole ? ' errors' : '' }}">
|
||||
<label for="userrole">{{ __('Role') }} <abbr title="{{ __('required') }}">*</abbr></label>
|
||||
<select name="userrole" required>
|
||||
|
@ -57,7 +33,15 @@
|
|||
{% if errors.userrole %}
|
||||
<span class="error">{{ errors.userrole | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="large{{ errors.email ? ' errors' : '' }}">
|
||||
<label for="email">{{ __('E-Mail') }} <abbr title="{{ __('required') }}">*</abbr></label>
|
||||
<input type="text" name="email" value="{{ old.email ? old.email : '' }}" required>
|
||||
{% if errors.email %}
|
||||
<span class="error">{{ errors.email | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="large{{ errors.password ? ' errors' : '' }}">
|
||||
<label for="password">{{ __('Password') }} <abbr title="{{ __('required') }}">*</abbr></label>
|
||||
|
@ -76,4 +60,4 @@
|
|||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% endblock %}
|
|
@ -3,6 +3,8 @@
|
|||
use Typemill\Events\OnSettingsLoaded;
|
||||
use Typemill\Events\OnPluginsLoaded;
|
||||
use Typemill\Events\OnSessionSegmentsLoaded;
|
||||
use Typemill\Events\OnRolesPermissionsLoaded;
|
||||
use Typemill\Events\OnResourcesLoaded;
|
||||
|
||||
/****************************
|
||||
* HIDE ERRORS BY DEFAULT *
|
||||
|
@ -109,6 +111,32 @@ $dispatcher->dispatch('onPluginsLoaded', new OnPluginsLoaded($pluginNames));
|
|||
# dispatch settings event and get all setting-updates from plugins
|
||||
$dispatcher->dispatch('onSettingsLoaded', new OnSettingsLoaded($settings))->getData();
|
||||
|
||||
|
||||
/**********************************
|
||||
* LOAD ROLES AND PERMISSIONS *
|
||||
**********************************/
|
||||
|
||||
# load roles and permissions
|
||||
$rolesAndPermissions = Typemill\Settings::loadRolesAndPermissions();
|
||||
|
||||
# dispatch roles so plugins can enhance them
|
||||
$rolesAndPermissions = $dispatcher->dispatch('onRolesPermissionsLoaded', new OnRolesPermissionsLoaded($rolesAndPermissions))->getData();
|
||||
|
||||
# load resources
|
||||
$resources = Typemill\Settings::loadResources();
|
||||
|
||||
# dispatch roles so plugins can enhance them
|
||||
$resources = $dispatcher->dispatch('onResourcesLoaded', new OnResourcesLoaded($resources))->getData();
|
||||
|
||||
# create acl-object
|
||||
$acl = Typemill\Settings::createAcl($rolesAndPermissions, $resources);
|
||||
|
||||
# add acl to container
|
||||
$container['acl'] = function($c) use ($acl)
|
||||
{
|
||||
return $acl;
|
||||
};
|
||||
|
||||
/******************************
|
||||
* ADD DISPATCHER TO CONTAINER *
|
||||
******************************/
|
||||
|
|
Loading…
Add table
Reference in a new issue