mirror of
https://github.com/typemill/typemill.git
synced 2025-08-04 21:27:41 +02:00
Version 1.1.6 User Role, Fieldsets and Refactoring
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,14 +1,11 @@
|
||||
cache/structure.txt
|
||||
cache/sitemap.xml
|
||||
cache/lastSitemap.txt
|
||||
cache/stats.txt
|
||||
cache
|
||||
settings/settings.yaml
|
||||
settings/users
|
||||
plugins/admin
|
||||
plugins/demo
|
||||
plugins/disqus
|
||||
plugins/download
|
||||
plugins/finalwords
|
||||
plugins/share
|
||||
plugins/version
|
||||
system/vendor
|
||||
tests
|
||||
|
2
cache/lastCache.txt
vendored
2
cache/lastCache.txt
vendored
@@ -1 +1 @@
|
||||
1526030510
|
||||
1527021720
|
@@ -1,6 +1,6 @@
|
||||
# Settings
|
||||
|
||||
As of Version 1.1.3 you can edit all settings in the new authoring panel of TYPEMILL. Just login to your typemill installation and go to settings. There you can edit:
|
||||
As of Version 1.1.3 you can edit all settings in the new authoring panel of TYPEMILL. Just visit the url `yourwebsite.com/tm/login` and go to settings after the login. There you can edit:
|
||||
|
||||
* The system (basic settings).
|
||||
* Themes (choose themes and configure it).
|
||||
@@ -17,4 +17,5 @@ There are some settings that are not available via the author panel. Most of the
|
||||
displayErrorDetails: true
|
||||
````
|
||||
|
||||
Don't forget to set it back to `false` before you deploy the website live. It is not secure to show the world your internal errors and many hosters will turn off all public error reports by default.
|
||||
Don't forget to set it back to `false` before you deploy the website live. It is not secure to show the world your internal errors and many hosters will turn off all public error reports by default.
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
After you have setup your TYPEMILL website, you can login to the author panel. The login url is
|
||||
|
||||
````
|
||||
https://yourwebsite.net/tm-author/login
|
||||
https://yourwebsite.net/tm/login
|
||||
````
|
||||
|
||||
You can also use the url `https://yourwebsite.net/setup` that redirects to the login screen.
|
||||
@@ -15,4 +15,5 @@ In the **settings area** of the author panel you can:
|
||||
* Activate and configure **plugins**.
|
||||
* Manage **users**.
|
||||
|
||||
the **content area** of the author-panel is not ready yet, but it is on it's way and will be published in near future. Then you can create and manage all the content of your website online. For time being you have to create your content offline e.g. with a markdown editor and upload your content files with a FTP software.
|
||||
the **content area** of the author-panel is not ready yet, but it is on it's way and will be published in near future. Then you can create and manage all the content of your website online. For time being you have to create your content offline e.g. with a markdown editor and upload your content files with a FTP software.
|
||||
|
||||
|
21
content/2_for-writers/60-lost-password.md
Normal file
21
content/2_for-writers/60-lost-password.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Lost Your Password?
|
||||
|
||||
TYPEMILL does not provide a password recovery, but there are two ways to create a new password.
|
||||
|
||||
## Is there another admin?
|
||||
|
||||
If there is another user with admin rights, then contact him. He can delete your user, create a new one and tell you the new password. Change the password immediately after login.
|
||||
|
||||
## No other admin?
|
||||
|
||||
If you are the only admin user, then please follow these steps:
|
||||
|
||||
* Connect to your website (e.g. via FTP).
|
||||
* Go to the folder `/settings` and backup the file `settings.yaml`.
|
||||
* Then delete the file `settings.yaml` on your server.
|
||||
* Go to `yoursite.com/setup`.
|
||||
* Fill out the form. This will create a new admin user and a fresh settings-file.
|
||||
* Upload your old settings-file, so your old settings are active again.
|
||||
* If not done before e.g. via FTP, delete the old admin-user in the user management now.
|
||||
|
||||
It might look a bit uncomfortable but it makes sure, that you are the owner of the website.
|
@@ -66,4 +66,35 @@ forms:
|
||||
|
||||
TYPEMILL will use these definitions and generate input fields for the author panel on the fly, so that the user can edit the values and customize the theme. If you have defined settings with the same name as the field name (e.g. `chapter`), then the input field in the author panel will automatically be prefilled with your settings from the YAML-file.
|
||||
|
||||
If you read the YAML-definition for input fields carefully, then you will notice that the definitions are pretty similar HTML: You simply define types and attributes like input-type, labels and placeholders. Nearly all valid field-types and field attributes are supported. You can find a detailed list in the [documentation for plugins](/plugin-developers/documentation/field-overview).
|
||||
If you have a lot of fields, you can even group some fields together in a fieldset like this:
|
||||
|
||||
````
|
||||
forms:
|
||||
fields:
|
||||
|
||||
chapter:
|
||||
type: text
|
||||
label: chapter
|
||||
placeholder: Add Name for Chapter
|
||||
required: true
|
||||
|
||||
MyFirstfieldset:
|
||||
type: fieldset
|
||||
legend: Last Modified
|
||||
fields:
|
||||
|
||||
modified:
|
||||
type: checkbox
|
||||
label: Activate Last Modified
|
||||
description: Show last modified date at the end of each page?
|
||||
|
||||
modifiedText:
|
||||
type: text
|
||||
label: Last Modified Text
|
||||
placeholder: Last Updated
|
||||
|
||||
````
|
||||
|
||||
The fields `modified` and `modifiedText` will then be grouped in a fieldset with the legend `Last Modified`.
|
||||
|
||||
If you read the YAML-definition for input fields carefully, then you will notice that the definitions are pretty similar to HTML: You simply define types and attributes like input-type, labels and placeholders. Nearly all valid field-types and field attributes are supported. You can find a detailed list in the [documentation for plugins](/plugin-developers/documentation/field-overview).
|
@@ -47,6 +47,7 @@ TYPEMILL accepts the following field type definitions:
|
||||
* textarea
|
||||
* tel
|
||||
* url
|
||||
* fieldset
|
||||
|
||||
A simple field definition looks like this:
|
||||
|
||||
@@ -174,6 +175,38 @@ SimpleCheckbox:
|
||||
description: Please check me
|
||||
````
|
||||
|
||||
## Using Fieldsets
|
||||
|
||||
If you have a lot of fields, you can group them togeter with a fieldset like this:
|
||||
|
||||
````
|
||||
forms:
|
||||
fields:
|
||||
|
||||
chapter:
|
||||
type: text
|
||||
label: chapter
|
||||
placeholder: Add Name for Chapter
|
||||
required: true
|
||||
|
||||
MyFirstfieldset:
|
||||
type: fieldset
|
||||
legend: Last Modified
|
||||
fields:
|
||||
|
||||
modified:
|
||||
type: checkbox
|
||||
label: Activate Last Modified
|
||||
description: Show last modified date at the end of each page?
|
||||
|
||||
modifiedText:
|
||||
type: text
|
||||
label: Last Modified Text
|
||||
placeholder: Last Updated
|
||||
````
|
||||
|
||||
The fields `modified` and `modifiedText` will then be grouped in a fieldset with the legend `Last Modified`.
|
||||
|
||||
## Example for a complete yaml configuration
|
||||
|
||||
To sum it up, this is a complete example of a yaml configuration file for a plugin with the meta-description, a default value and a field definition for user input:
|
||||
@@ -201,3 +234,4 @@ forms:
|
||||
block: Block
|
||||
classic: Classic
|
||||
````
|
||||
|
||||
|
@@ -7,6 +7,7 @@ use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
use Typemill\Models\Validation;
|
||||
use Typemill\Models\User;
|
||||
use Typemill\Models\WriteYaml;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
@@ -34,9 +35,37 @@ class AuthController extends Controller
|
||||
|
||||
public function show(Request $request, Response $response, $args)
|
||||
{
|
||||
$this->c->view->render($response, '/auth/login.twig');
|
||||
}
|
||||
$data = array();
|
||||
|
||||
/* check previous login attemps */
|
||||
$yaml = new WriteYaml();
|
||||
$logins = $yaml->getYaml('settings/users', '.logins');
|
||||
$userIP = $this->getUserIP();
|
||||
$userLogins = isset($logins[$userIP]) ? count($logins[$userIP]) : false;
|
||||
|
||||
if($userLogins)
|
||||
{
|
||||
/* get the latest */
|
||||
$lastLogin = intval($logins[$userIP][$userLogins-1]);
|
||||
|
||||
/* if last login is longer than 60 seconds ago, clear it. */
|
||||
if(time() - $lastLogin > 60)
|
||||
{
|
||||
unset($logins[$userIP]);
|
||||
$yaml->updateYaml('settings/users', '.logins', $logins);
|
||||
}
|
||||
|
||||
/* Did the user made three login attemps that failed? */
|
||||
elseif($userLogins >= 3)
|
||||
{
|
||||
$timeleft = 60 - (time() - $lastLogin);
|
||||
$data['messages'] = array('time' => $timeleft, 'error' => array( 'Too many bad logins. Please wait.'));
|
||||
}
|
||||
}
|
||||
|
||||
$this->c->view->render($response, '/auth/login.twig', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* signin an existing user
|
||||
*
|
||||
@@ -47,6 +76,36 @@ class AuthController extends Controller
|
||||
|
||||
public function login(Request $request, Response $response)
|
||||
{
|
||||
/* log user attemps to authenticate */
|
||||
$yaml = new WriteYaml();
|
||||
$logins = $yaml->getYaml('settings/users', '.logins');
|
||||
$userIP = $this->getUserIP();
|
||||
$userLogins = isset($logins[$userIP]) ? count($logins[$userIP]) : false;
|
||||
|
||||
/* if there have been user logins before. You have to do this again, because user does not always refresh the login page and old login attemps are stored. */
|
||||
if($userLogins)
|
||||
{
|
||||
/* get the latest */
|
||||
$lastLogin = intval($logins[$userIP][$userLogins-1]);
|
||||
|
||||
/* if last login is longer than 60 seconds ago, clear it and add this attempt */
|
||||
if(time() - $lastLogin > 60)
|
||||
{
|
||||
unset($logins[$userIP]);
|
||||
$yaml->updateYaml('settings/users', '.logins', $logins);
|
||||
}
|
||||
|
||||
/* Did the user made three login attemps that failed? */
|
||||
elseif($userLogins >= 2)
|
||||
{
|
||||
$logins[$userIP][] = time();
|
||||
$yaml->updateYaml('settings/users', '.logins', $logins);
|
||||
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
}
|
||||
}
|
||||
|
||||
/* authentication */
|
||||
$params = $request->getParams();
|
||||
$validation = new Validation();
|
||||
|
||||
@@ -58,14 +117,26 @@ class AuthController extends Controller
|
||||
if($userdata && password_verify($params['password'], $userdata['password']))
|
||||
{
|
||||
$user->login($userdata['username']);
|
||||
|
||||
/* clear the user login attemps */
|
||||
if($userLogins)
|
||||
{
|
||||
unset($logins[$userIP]);
|
||||
$yaml->updateYaml('settings/users', '.logins', $logins);
|
||||
}
|
||||
|
||||
return $response->withRedirect($this->c->router->pathFor('settings.show'));
|
||||
}
|
||||
}
|
||||
|
||||
/* if authentication failed, add attempt to log file */
|
||||
$logins[$userIP][] = time();
|
||||
$yaml->updateYaml('settings/users', '.logins', $logins);
|
||||
|
||||
$this->c->flash->addMessage('error', 'Ups, credentials were wrong, please try again.');
|
||||
$this->c->flash->addMessage('error', 'Ups, wrong password or username, please try again.');
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* log out a user
|
||||
*
|
||||
@@ -82,5 +153,27 @@ class AuthController extends Controller
|
||||
}
|
||||
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
}
|
||||
}
|
||||
|
||||
private function getUserIP()
|
||||
{
|
||||
$client = @$_SERVER['HTTP_CLIENT_IP'];
|
||||
$forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||
$remote = $_SERVER['REMOTE_ADDR'];
|
||||
|
||||
if(filter_var($client, FILTER_VALIDATE_IP))
|
||||
{
|
||||
$ip = $client;
|
||||
}
|
||||
elseif(filter_var($forward, FILTER_VALIDATE_IP))
|
||||
{
|
||||
$ip = $forward;
|
||||
}
|
||||
else
|
||||
{
|
||||
$ip = $remote;
|
||||
}
|
||||
|
||||
return $ip;
|
||||
}
|
||||
}
|
@@ -20,6 +20,11 @@ abstract class Controller
|
||||
$data = $this->c->dispatcher->dispatch('onPageReady', new OnPageReady($data))->getData();
|
||||
|
||||
unset($_SESSION['old']);
|
||||
|
||||
$response = $response->withAddedHeader('X-Content-Type-Options', 'nosniff');
|
||||
$response = $response->withAddedHeader('X-Frame-Options', 'SAMEORIGIN');
|
||||
$response = $response->withAddedHeader('X-XSS-Protection', '1;mode=block');
|
||||
|
||||
return $this->c->view->render($response, $route, $data);
|
||||
}
|
||||
|
||||
|
@@ -90,7 +90,7 @@ class SettingsController extends Controller
|
||||
if(isset($themeSettings['forms']['fields']))
|
||||
{
|
||||
$fields = $this->getFields($userSettings, 'themes', $themeName, $themeSettings);
|
||||
|
||||
|
||||
/* overwrite original theme form definitions with enhanced form objects */
|
||||
$themedata[$themeName]['forms']['fields'] = $fields;
|
||||
}
|
||||
@@ -177,57 +177,73 @@ class SettingsController extends Controller
|
||||
/* then iterate through the fields */
|
||||
foreach($objectSettings['forms']['fields'] as $fieldName => $fieldConfigs)
|
||||
{
|
||||
/* and create a new field object with the field name and the field configurations. */
|
||||
$field = new Field($fieldName, $fieldConfigs);
|
||||
|
||||
/* you have to prefil the value for the field with default settings, user settings or old user-input from form */
|
||||
$userValue = false;
|
||||
|
||||
/* first, add the default values from the original plugin or theme settings. Ignore checkboxes, otherwiese they might be always checked */
|
||||
if(isset($objectSettings['settings'][$fieldName]))
|
||||
if($fieldConfigs['type'] == 'fieldset')
|
||||
{
|
||||
$userValue = $objectSettings['settings'][$fieldName];
|
||||
}
|
||||
|
||||
/* now overwrite them with the local stored user settings */
|
||||
if(isset($userSettings[$objectType][$objectName][$fieldName]))
|
||||
{
|
||||
$userValue = $userSettings[$objectType][$objectName][$fieldName];
|
||||
}
|
||||
|
||||
/* overwrite it with old input in form, if exists */
|
||||
if(isset($_SESSION['old'][$objectName][$fieldName]))
|
||||
{
|
||||
$userValue = $_SESSION['old'][$objectName][$fieldName];
|
||||
}
|
||||
|
||||
/* now we have set the uservalue for the field. Prepopulate the field object with it now */
|
||||
if($field->getType() == "textarea")
|
||||
{
|
||||
if($userValue)
|
||||
{
|
||||
$field->setContent($userValue);
|
||||
}
|
||||
}
|
||||
elseif($field->getType() == "checkbox")
|
||||
{
|
||||
/* needs special treatment, because field does not exist in settings if unchecked by user */
|
||||
if(isset($userSettings[$objectType][$objectName][$fieldName]))
|
||||
{
|
||||
$field->setAttribute('checked', 'checked');
|
||||
}
|
||||
else
|
||||
{
|
||||
$field->unsetAttribute('checked');
|
||||
}
|
||||
/* Create an array for the subsettings of the fieldset with the same structure and data as the original settings array */
|
||||
$subSettings = $objectSettings;
|
||||
$subSettings['forms'] = $fieldConfigs;
|
||||
|
||||
$fieldset = array();
|
||||
$fieldset['type'] = 'fieldset';
|
||||
$fieldset['legend'] = $fieldConfigs['legend'];
|
||||
$fieldset['fields'] = $this->getFields($userSettings, $objectType, $objectName, $subSettings);
|
||||
$fields[] = $fieldset;
|
||||
}
|
||||
else
|
||||
{
|
||||
$field->setAttributeValue('value', $userValue);
|
||||
}
|
||||
/* and create a new field object with the field name and the field configurations. */
|
||||
$field = new Field($fieldName, $fieldConfigs);
|
||||
|
||||
/* you have to prefil the value for the field with default settings, user settings or old user-input from form */
|
||||
$userValue = false;
|
||||
|
||||
/* add the field to the field-List with the plugin-name as key */
|
||||
$fields[] = $field;
|
||||
/* first, add the default values from the original plugin or theme settings. Ignore checkboxes, otherwiese they might be always checked */
|
||||
if(isset($objectSettings['settings'][$fieldName]))
|
||||
{
|
||||
$userValue = $objectSettings['settings'][$fieldName];
|
||||
}
|
||||
|
||||
/* now overwrite them with the local stored user settings */
|
||||
if(isset($userSettings[$objectType][$objectName][$fieldName]))
|
||||
{
|
||||
$userValue = $userSettings[$objectType][$objectName][$fieldName];
|
||||
}
|
||||
|
||||
/* overwrite it with old input in form, if exists */
|
||||
if(isset($_SESSION['old'][$objectName][$fieldName]))
|
||||
{
|
||||
$userValue = $_SESSION['old'][$objectName][$fieldName];
|
||||
}
|
||||
|
||||
/* now we have set the uservalue for the field. Prepopulate the field object with it now */
|
||||
if($field->getType() == "textarea")
|
||||
{
|
||||
if($userValue)
|
||||
{
|
||||
$field->setContent($userValue);
|
||||
}
|
||||
}
|
||||
elseif($field->getType() == "checkbox")
|
||||
{
|
||||
/* needs special treatment, because field does not exist in settings if unchecked by user */
|
||||
if(isset($userSettings[$objectType][$objectName][$fieldName]))
|
||||
{
|
||||
$field->setAttribute('checked', 'checked');
|
||||
}
|
||||
else
|
||||
{
|
||||
$field->unsetAttribute('checked');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$field->setAttributeValue('value', $userValue);
|
||||
}
|
||||
|
||||
/* add the field to the field-List with the plugin-name as key */
|
||||
$fields[] = $field;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
@@ -331,13 +347,31 @@ class SettingsController extends Controller
|
||||
/* fetch the original settings from the folder (plugin or theme) to get the field definitions */
|
||||
$originalSettings = \Typemill\Settings::getObjectSettings($objectType, $objectName);
|
||||
|
||||
if($originalSettings)
|
||||
if(isset($originalSettings['forms']['fields']))
|
||||
{
|
||||
/* flaten the multi-dimensional array with fieldsets to a one-dimensional array */
|
||||
$originalFields = array();
|
||||
foreach($originalSettings['forms']['fields'] as $fieldName => $fieldValue)
|
||||
{
|
||||
if(isset($fieldValue['fields']))
|
||||
{
|
||||
foreach($fieldValue['fields'] as $subFieldName => $subFieldValue)
|
||||
{
|
||||
$originalFields[$subFieldName] = $subFieldValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$originalFields[$fieldName] = $fieldValue;
|
||||
}
|
||||
}
|
||||
|
||||
/* take the user input data and iterate over all fields and values */
|
||||
foreach($userInput as $fieldName => $fieldValue)
|
||||
{
|
||||
/* get the corresponding field definition from original plugin settings */
|
||||
$fieldDefinition = isset($originalSettings['forms']['fields'][$fieldName]) ? $originalSettings['forms']['fields'][$fieldName] : false;
|
||||
$fieldDefinition = isset($originalFields[$fieldName]) ? $originalFields[$fieldName] : false;
|
||||
|
||||
if($fieldDefinition)
|
||||
{
|
||||
/* validate user input for this field */
|
||||
@@ -345,18 +379,23 @@ class SettingsController extends Controller
|
||||
}
|
||||
if(!$fieldDefinition && $fieldName != 'active')
|
||||
{
|
||||
$_SESSION['errors'][$objectName][$fieldName] = 'This field is not defined!';
|
||||
$_SESSION['errors'][$objectName][$fieldName] = array('This field is not defined!');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************
|
||||
** 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']))
|
||||
@@ -428,12 +467,25 @@ class SettingsController extends Controller
|
||||
public function updateUser($request, $response, $args)
|
||||
{
|
||||
if($request->isPost())
|
||||
{
|
||||
{
|
||||
$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'], 'email' => $params['email'], 'userrole' => $params['userrole']);
|
||||
@@ -442,14 +494,14 @@ class SettingsController extends Controller
|
||||
{
|
||||
$user->updateUser($userdata);
|
||||
$this->c->flash->addMessage('info', 'Saved all changes');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.list'));
|
||||
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.list'));
|
||||
return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $params['username']]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,6 +517,16 @@ class SettingsController extends Controller
|
||||
$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']))
|
||||
{
|
||||
|
34
system/Extensions/TwigUserExtension.php
Normal file
34
system/Extensions/TwigUserExtension.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Extensions;
|
||||
|
||||
class TwigUserExtension extends \Twig_Extension
|
||||
{
|
||||
public function getFunctions()
|
||||
{
|
||||
return [
|
||||
new \Twig_SimpleFunction('is_role', array($this, 'isRole' )),
|
||||
new \Twig_SimpleFunction('get_username', array($this, 'getUsername' ))
|
||||
];
|
||||
}
|
||||
|
||||
public function isRole($role)
|
||||
{
|
||||
if(isset($_SESSION['role']) && $_SESSION['role'] == $role)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getUsername()
|
||||
{
|
||||
if(isset($_SESSION['user']))
|
||||
{
|
||||
return $_SESSION['user'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
32
system/Middleware/RedirectIfNoAdmin.php
Normal file
32
system/Middleware/RedirectIfNoAdmin.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Middleware;
|
||||
|
||||
use Slim\Interfaces\RouterInterface;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
class RedirectIfNoAdmin
|
||||
{
|
||||
protected $router;
|
||||
|
||||
public function __construct(RouterInterface $router, $flash)
|
||||
{
|
||||
$this->router = $router;
|
||||
}
|
||||
|
||||
public function __invoke(Request $request, Response $response, $next)
|
||||
{
|
||||
if(!isset($_SESSION['login']) || !isset($_SESSION['role']))
|
||||
{
|
||||
$response = $response->withRedirect($this->router->pathFor('auth.show'));
|
||||
}
|
||||
|
||||
if($_SESSION['role'] != 'administrator')
|
||||
{
|
||||
$response = $response->withRedirect($this->router->pathFor('content.show'));
|
||||
}
|
||||
|
||||
return $next($request, $response);
|
||||
}
|
||||
}
|
@@ -21,7 +21,7 @@ class RedirectIfUnauthenticated
|
||||
{
|
||||
$response = $response->withRedirect($this->router->pathFor('auth.show'));
|
||||
}
|
||||
|
||||
|
||||
return $next($request, $response);
|
||||
}
|
||||
}
|
@@ -13,12 +13,14 @@ class User extends WriteYaml
|
||||
|
||||
/* get all plugins folder */
|
||||
$users = array_diff(scandir($userDir), array('..', '.'));
|
||||
|
||||
|
||||
$cleanUser = array();
|
||||
foreach($users as $key => $user)
|
||||
{
|
||||
if($user == '.logins'){ continue; }
|
||||
$cleanUser[] = str_replace('.yaml', '', $user);
|
||||
}
|
||||
|
||||
return $cleanUser;
|
||||
}
|
||||
|
||||
@@ -75,8 +77,13 @@ class User extends WriteYaml
|
||||
|
||||
public function login($username)
|
||||
{
|
||||
$_SESSION['user'] = $username;
|
||||
$_SESSION['login'] = true;
|
||||
$user = $this->getUser($username);
|
||||
if($user)
|
||||
{
|
||||
$_SESSION['user'] = $user['username'];
|
||||
$_SESSION['role'] = $user['userrole'];
|
||||
$_SESSION['login'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function generatePassword($password)
|
||||
|
@@ -7,6 +7,7 @@ use Typemill\Controllers\SettingsController;
|
||||
use Typemill\Controllers\ContentController;
|
||||
use Typemill\Middleware\RedirectIfUnauthenticated;
|
||||
use Typemill\Middleware\RedirectIfAuthenticated;
|
||||
use Typemill\Middleware\RedirectIfNoAdmin;
|
||||
|
||||
if($settings['settings']['setup'])
|
||||
{
|
||||
@@ -26,23 +27,26 @@ else
|
||||
$app->get('/setup/welcome', AuthController::class . ':redirect')->setName('setup.welcome');
|
||||
}
|
||||
|
||||
$app->get('/tm-author', AuthController::class . ':redirect');
|
||||
$app->get('/tm-author/login', AuthController::class . ':show')->setName('auth.show')->add(new RedirectIfAuthenticated($container['router']));
|
||||
$app->post('/tm-author/login', AuthController::class . ':login')->setName('auth.login')->add(new RedirectIfAuthenticated($container['router']));
|
||||
$app->get('/tm-author/logout', AuthController::class . ':logout')->setName('auth.logout')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->get('/tm-author/settings', SettingsController::class . ':showSettings')->setName('settings.show')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->post('/tm-author/settings', SettingsController::class . ':saveSettings')->setName('settings.save')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->get('/tm-author/themes', SettingsController::class . ':showThemes')->setName('themes.show')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->post('/tm-author/themes', SettingsController::class . ':saveThemes')->setName('themes.save')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->get('/tm-author/plugins', SettingsController::class . ':showPlugins')->setName('plugins.show')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->post('/tm-author/plugins', SettingsController::class . ':savePlugins')->setName('plugins.save')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->get('/tm-author/user/new', SettingsController::class . ':newUser')->setName('user.new')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->post('/tm-author/user/create', SettingsController::class . ':createUser')->setName('user.create')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->post('/tm-author/user/update', SettingsController::class . ':updateUser')->setName('user.update')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->post('/tm-author/user/delete', SettingsController::class . ':deleteUser')->setName('user.delete')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->get('/tm-author/user/{username}', SettingsController::class . ':showUser')->setName('user.show')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->get('/tm-author/user', SettingsController::class . ':listUser')->setName('user.list')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->get('/tm-author/content', ContentController::class . ':showContent')->setName('content.show')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->get('/tm', AuthController::class . ':redirect');
|
||||
$app->get('/tm/login', AuthController::class . ':show')->setName('auth.show')->add(new RedirectIfAuthenticated($container['router']));
|
||||
$app->post('/tm/login', AuthController::class . ':login')->setName('auth.login')->add(new RedirectIfAuthenticated($container['router']));
|
||||
$app->get('/tm/logout', AuthController::class . ':logout')->setName('auth.logout')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
|
||||
$app->get('/tm/content', ContentController::class . ':showContent')->setName('content.show')->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->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']));
|
||||
|
||||
foreach($routes as $pluginRoute)
|
||||
{
|
||||
|
@@ -41,7 +41,9 @@ class Settings
|
||||
'userPath' => $rootPath . 'settings' . DIRECTORY_SEPARATOR . 'users',
|
||||
'authorPath' => __DIR__ . DIRECTORY_SEPARATOR . 'author' . DIRECTORY_SEPARATOR,
|
||||
'contentFolder' => 'content',
|
||||
'version' => '1.1.5',
|
||||
'cache' => true,
|
||||
'cachePath' => $rootPath . 'cache',
|
||||
'version' => '1.1.4',
|
||||
'setup' => true,
|
||||
'welcome' => true
|
||||
];
|
||||
|
@@ -22,11 +22,18 @@
|
||||
<span class="error">{{ errors.password | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</fieldset>
|
||||
</fieldset>
|
||||
|
||||
<div class="loginarea" id="loginarea">
|
||||
<input type="submit" value="Login" id="loginbutton" class="loginbutton" />
|
||||
{{ csrf_field() | raw }}
|
||||
|
||||
{% if messages.time %}
|
||||
<div id="counter" class="counter">wait <span id="wait">{{ messages.time }}</span> sec</div>
|
||||
<div class="forgotpw"><a href="https://typemill.net/writers/forgot-password" target="_blank">Forgot password?</a></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<input type="submit" value="Login" />
|
||||
{{ csrf_field() | raw }}
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
File diff suppressed because it is too large
Load Diff
32
system/author/js/auth.js
Normal file
32
system/author/js/auth.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/*************************************
|
||||
** LOGIN TIMER **
|
||||
*************************************/
|
||||
|
||||
var wait = document.getElementById('wait');
|
||||
|
||||
if(wait)
|
||||
{
|
||||
var loginbtn = document.getElementById("loginbutton");
|
||||
var seconds = parseInt(wait.innerHTML);
|
||||
|
||||
loginbtn.disabled = true;
|
||||
loginbtn.value = '';
|
||||
|
||||
var counter = setInterval(function () {
|
||||
|
||||
seconds = seconds - 1;
|
||||
wait.innerHTML = seconds;
|
||||
|
||||
if (seconds == 0) {
|
||||
loginbtn.disabled = false;
|
||||
loginbtn.value = 'Login';
|
||||
var countdown = document.getElementById("counter");
|
||||
// var flash = document.getElementById("flash-message");
|
||||
|
||||
countdown.parentNode.removeChild(countdown);
|
||||
// flash.parentNode.removeChild(flash);
|
||||
|
||||
clearInterval(counter);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
@@ -248,7 +248,7 @@
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
** COLOR PICKER **
|
||||
*************************************/
|
||||
|
@@ -27,5 +27,6 @@
|
||||
{% block content %}{% endblock %}
|
||||
|
||||
</div>
|
||||
<script src="{{ base_url }}/system/author/js/auth.js"></script>
|
||||
</body>
|
||||
</html>
|
@@ -1,17 +1,19 @@
|
||||
<nav id="sidebar-menu" class="sidebar-menu">
|
||||
<div id="mobile-menu" class="menu-action">Menu <span class="button-arrow"></span></div>
|
||||
<h3>Settings</h3>
|
||||
<ul class="menu-list">
|
||||
<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>
|
||||
{% 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">
|
||||
<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 %}
|
||||
</nav>
|
@@ -1,6 +1,6 @@
|
||||
{% if flash.getMessage('info') %}
|
||||
|
||||
<div class="alert alert-info">
|
||||
<div class="alert alert-info" id="flash-message">
|
||||
{{ flash.getMessage('info') | first }}
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
{% if messages.info %}
|
||||
|
||||
<div class="alert alert-error">
|
||||
<div class="alert alert-error" id="flash-message">
|
||||
{{ messages.info | first }}
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
{% if flash.getMessage('error') %}
|
||||
|
||||
<div class="alert alert-error">
|
||||
<div class="alert alert-error" id="flash-message">
|
||||
{{ flash.getMessage('error') | first }}
|
||||
</div>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
{% if messages.error %}
|
||||
|
||||
<div class="alert alert-error">
|
||||
<div class="alert alert-error" id="flash-message">
|
||||
{{ messages.error | first }}
|
||||
</div>
|
||||
|
||||
|
@@ -4,8 +4,12 @@
|
||||
</div>
|
||||
<ul class="navi-items">
|
||||
<li><a href="{{ path_for('content.show') }}"{{ navigation ? 'class="active"' : '' }}><i class="icon-doc-text"></i><span class="nav-label"> Content</span></a></li><li>
|
||||
<a href="{{ path_for('settings.show') }}"{{ users ? 'class="active"' : '' }}><i class="icon-cog"></i><span class="nav-label"> Settings</span></a></li><li>
|
||||
<a href="{{ base_url }}"><i class="icon-link-ext"></i><span class="nav-label"> Website</span></a></li><li>
|
||||
{% if is_role('administrator') %}
|
||||
<a href="{{ path_for('settings.show') }}"{{ users ? 'class="active"' : '' }}><i class="icon-cog"></i><span class="nav-label"> Settings</span></a></li><li>
|
||||
{% else %}
|
||||
<a href="{{ path_for('user.show', {'username' : get_username() }) }}"{{ users ? 'class="active"' : '' }}><i class="icon-cog"></i><span class="nav-label"> Account</span></a></li><li>
|
||||
{% endif %}
|
||||
<a href="{{ base_url }}"><i class="icon-link-ext"></i><span class="nav-label"> View Site</span></a></li><li>
|
||||
<a href="{{ path_for('auth.logout') }}"><i class="icon-off"></i><span class="nav-label"> Logout</span></a></li>
|
||||
</ul>
|
||||
</nav>
|
@@ -28,15 +28,17 @@
|
||||
</div>
|
||||
</header>
|
||||
<div id="{{ pluginName }}" class="fc-plugin-version update-banner">{{ plugin.version ? plugin.version : 'Unknown' }}</div>
|
||||
|
||||
<p>{{ plugin.description ? plugin.description : 'No description' }}</p>
|
||||
|
||||
<ul class="cardInfo">
|
||||
<li>{{ plugin.version ? plugin.version : 'Unknown' }}</li><li>
|
||||
{{ plugin.licence ? plugin.licence : 'Unkown' }}</li><li>
|
||||
by {{ plugin.author ? plugin.author : 'Unknown' }}</li>{% if plugin.homepage %}<li>
|
||||
<a href="{{ plugin.homepage}}" target="blank">Web</a></li>{% endif %}
|
||||
</ul>
|
||||
<div class="cardDescPlugin">
|
||||
<p>{{ plugin.description ? plugin.description : 'No description' }}</p>
|
||||
|
||||
<ul class="cardInfo">
|
||||
<li>{{ plugin.version ? plugin.version : 'Unknown' }}</li><li>
|
||||
{{ plugin.licence ? plugin.licence : 'Unkown' }}</li><li>
|
||||
by {{ plugin.author ? plugin.author : 'Unknown' }}</li>{% if plugin.homepage %}<li>
|
||||
<a href="{{ plugin.homepage}}" target="blank">Web</a></li>{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="cardInner cardFields{{ errors[pluginName] ? ' open' : '' }}">
|
||||
|
||||
{% for field in plugin.forms.fields %}
|
||||
|
@@ -17,6 +17,7 @@
|
||||
<form method="POST" action="{{ path_for('themes.save') }}">
|
||||
|
||||
<fieldset class="card{{ errors[themeName] ? ' errors' : '' }}">
|
||||
|
||||
<div class="cardInner cardHead">
|
||||
|
||||
{% if theme.img %}
|
||||
@@ -24,39 +25,54 @@
|
||||
{% else %}
|
||||
<div class="no-preview">No Preview</div>
|
||||
{% endif %}
|
||||
|
||||
<div id="{{ themeName }}" class="fc-theme-version update-banner">{{ theme.version ? theme.version : 'Unknown' }}</div>
|
||||
|
||||
<div class="cardContent">
|
||||
<h2>{{ themeName }}</h2>
|
||||
<p>{{ theme.description }}</p>
|
||||
<ul class="cardInfo">
|
||||
<li>{{ theme.version ? theme.version : 'Unknown' }}</li><li>
|
||||
{{ theme.licence ? theme.licence : 'Unkown' }}</li><li>
|
||||
by {{ theme.author ? theme.author : 'Unknown' }}</li>{% if theme.homepage %}<li>
|
||||
<a href="{{ theme.homepage}}" target="blank">Web</a></li>{% endif %}
|
||||
</ul>
|
||||
<div id="{{ themeName }}" class="fc-theme-version update-banner">{{ theme.version ? theme.version : 'Unknown' }}</div>
|
||||
|
||||
<div class="cardDescription">
|
||||
<h2>{{ themeName }}</h2>
|
||||
<p>{{ theme.description }}</p>
|
||||
<ul class="cardInfo">
|
||||
<li>{{ theme.version ? theme.version : 'Unknown' }}</li><li>
|
||||
{{ theme.licence ? theme.licence : 'Unkown' }}</li><li>
|
||||
by {{ theme.author ? theme.author : 'Unknown' }}</li>{% if theme.homepage %}<li>
|
||||
<a href="{{ theme.homepage}}" target="blank">Web</a></li>{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="cardInner cardFields{{ errors[themeName] ? ' open' : '' }}">
|
||||
|
||||
{% for field in theme.forms.fields %}
|
||||
|
||||
{% include '/partials/forms.twig' with {'itemName' : themeName, 'object' : 'themes' } %}
|
||||
|
||||
{% if field.type == 'fieldset' %}
|
||||
|
||||
<fieldset class="subfield">
|
||||
<legend>{{ field.legend }}</legend>
|
||||
{% for field in field.fields %}
|
||||
{% include '/partials/forms.twig' with {'itemName' : themeName, 'object' : 'themes' } %}
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
|
||||
{% else %}
|
||||
|
||||
{% include '/partials/forms.twig' with {'itemName' : themeName, 'object' : 'themes' } %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="theme" value="{{ themeName }}">
|
||||
|
||||
<div class="medium">
|
||||
<button type="button" class="theme-button fc-settings{{ (settings.theme == themeName) ? ' active' : '' }}{{ theme.forms.fields|length > 0 ? ' has-settings' : ' no-settings'}}">{{ theme.forms.fields|length > 0 ? 'Settings <span class="button-arrow"></span>' : 'No Settings'}}</button>
|
||||
</div>
|
||||
<div class="medium">
|
||||
<input type="submit" value="Save Theme" />
|
||||
</div>
|
||||
|
||||
<div class="button-box">
|
||||
<input type="hidden" name="theme" value="{{ themeName }}">
|
||||
|
||||
<div class="medium">
|
||||
<button type="button" class="theme-button fc-settings{{ (settings.theme == themeName) ? ' active' : '' }}{{ theme.forms.fields|length > 0 ? ' has-settings' : ' no-settings'}}">{{ theme.forms.fields|length > 0 ? 'Settings <span class="button-arrow"></span>' : 'No Settings'}}</button>
|
||||
</div>
|
||||
<div class="medium">
|
||||
<input type="submit" value="Save Theme" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
|
||||
<section id="user" class="settings">
|
||||
|
||||
<header>
|
||||
<header class="headline">
|
||||
<h1>Edit User</h1>
|
||||
</header>
|
||||
|
||||
@@ -32,17 +32,19 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<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>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% if errors.userrole %}
|
||||
<span class="error">{{ errors.userrole | 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>
|
||||
{% 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>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
|
||||
<section id="users" class="settings">
|
||||
|
||||
<header>
|
||||
<header class="headline">
|
||||
<h1>All Users</h1>
|
||||
</header>
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
|
||||
<section id="new-user" class="settings">
|
||||
|
||||
<header>
|
||||
<header class="headline">
|
||||
<h1>Create New User</h1>
|
||||
</header>
|
||||
|
||||
|
@@ -7,6 +7,8 @@ use Typemill\Events\OnPluginsLoaded;
|
||||
* START SESSION *
|
||||
************************/
|
||||
|
||||
ini_set( 'session.cookie_httponly', 1 );
|
||||
session_name('typemill_session');
|
||||
session_start();
|
||||
|
||||
/****************************
|
||||
@@ -133,7 +135,7 @@ $container['view'] = function ($container)
|
||||
$path = array($container->get('settings')['themePath'], $container->get('settings')['authorPath']);
|
||||
|
||||
$view = new \Slim\Views\Twig( $path, [
|
||||
'cache' => false,
|
||||
'cache' => $container->get('settings')['cache'] ? $container->get('settings')['cachePath'] : false,
|
||||
'autoescape' => false,
|
||||
'debug' => true
|
||||
]);
|
||||
@@ -143,6 +145,7 @@ $container['view'] = function ($container)
|
||||
$view->addExtension(new Slim\Views\TwigExtension($container['router'], $basePath));
|
||||
$view->addExtension(new Twig_Extension_Debug());
|
||||
$view->addExtension(new Typemill\Extensions\TwigCsrfExtension($container['csrf']));
|
||||
$view->addExtension(new Typemill\Extensions\TwigUserExtension());
|
||||
|
||||
/* use {{ base_url() }} in twig templates */
|
||||
$view['base_url'] = $container['request']->getUri()->getBaseUrl();
|
||||
|
@@ -3,14 +3,17 @@
|
||||
{% import _self as macros %}
|
||||
|
||||
{% for element in navigation %}
|
||||
|
||||
{% set depth = element.keyPathArray|length %}
|
||||
|
||||
{% if element.activeParent %}
|
||||
<li class="{{ element.elementType }} level-{{ element.keyPathArray|length }} active parent">
|
||||
<li class="{{ element.elementType }} level-{{ depth }} active parent">
|
||||
{% elseif element.active %}
|
||||
<li class="{{ element.elementType }} level-{{ element.keyPathArray|length }} active">
|
||||
<li class="{{ element.elementType }} level-{{ depth }} active">
|
||||
{% else %}
|
||||
<li class="{{ element.elementType }} level-{{ element.keyPathArray|length }}">
|
||||
<li class="{{ element.elementType }} level-{{ depth }}">
|
||||
{% endif %}
|
||||
{% if element.elementType == 'folder' %}
|
||||
{% if (element.elementType == 'folder') %}
|
||||
<a href="{{ element.urlAbs }}">{{ element.name|title }}</a>
|
||||
<ul>
|
||||
{{ macros.loop_over(element.folderContent) }}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
name: Typemill Theme
|
||||
version: 1.0.6
|
||||
description: The standard theme for Typemill. Responsive, minimal and without any dependencies. It uses the system fonts Calibri and Helvetica. JavaScript is only used for code highlighting. Skip it, if you don't need it.
|
||||
version: 1.0.7
|
||||
description: The standard theme for Typemill. Responsive, minimal and without any dependencies. It uses the system fonts Calibri and Helvetica. No JavaScript is used.
|
||||
author: Sebastian Schürmanns
|
||||
homepage: http://typemill.net
|
||||
licence: MIT
|
||||
@@ -17,43 +17,51 @@ forms:
|
||||
|
||||
chapter:
|
||||
type: text
|
||||
label: chapter
|
||||
label: Text For Chapter
|
||||
placeholder: Add Name for Chapter
|
||||
required: true
|
||||
|
||||
start:
|
||||
type: text
|
||||
label: Start-Button
|
||||
label: Label For Start Button
|
||||
placeholder: Add Label for Start-Button
|
||||
required: true
|
||||
|
||||
modified:
|
||||
type: checkbox
|
||||
label: Last Updated
|
||||
description: Show last updated note at the end of each page?
|
||||
fieldset1:
|
||||
type: fieldset
|
||||
legend: Last Modified
|
||||
fields:
|
||||
modified:
|
||||
type: checkbox
|
||||
label: Activate Last Modified
|
||||
description: Show last modified date at the end of each page?
|
||||
|
||||
modifiedText:
|
||||
type: text
|
||||
label: Last Updated Text
|
||||
placeholder: Last Updated
|
||||
modifiedText:
|
||||
type: text
|
||||
label: Last Modified Text
|
||||
placeholder: Last Updated
|
||||
|
||||
modifiedFormat:
|
||||
type: select
|
||||
label: Last Updated Format
|
||||
placeholder: 'Add name of theme'
|
||||
options:
|
||||
'm/d/Y': 01/20/2020
|
||||
'd.m.Y': 20.01.2020
|
||||
modifiedFormat:
|
||||
type: select
|
||||
label: Last Modified Format
|
||||
placeholder: 'Add name of theme'
|
||||
options:
|
||||
'm/d/Y': 01/20/2020
|
||||
'd.m.Y': 20.01.2020
|
||||
|
||||
social:
|
||||
type: checkbox
|
||||
label: Share Links
|
||||
description: Activate Share Links On Page?
|
||||
fieldset2:
|
||||
type: fieldset
|
||||
legend: Share
|
||||
fields:
|
||||
social:
|
||||
type: checkbox
|
||||
label: Activate Share
|
||||
description: Activate Share Buttons On Page?
|
||||
|
||||
socialbuttons:
|
||||
type: checkboxlist
|
||||
label: Select Share buttons
|
||||
options:
|
||||
facebook: Facebook
|
||||
twitter: Twitter
|
||||
xing: Xing
|
||||
socialbuttons:
|
||||
type: checkboxlist
|
||||
label: Select Share Buttons
|
||||
options:
|
||||
facebook: Facebook
|
||||
twitter: Twitter
|
||||
xing: Xing
|
Reference in New Issue
Block a user