Files
Grav-Admin-Plugin/admin.php

895 lines
29 KiB
PHP
Raw Normal View History

2014-08-05 13:06:38 -07:00
<?php
namespace Grav\Plugin;
2015-12-10 12:07:36 +01:00
use Grav\Common\File\CompiledYamlFile;
use Grav\Common\Grav;
use Grav\Common\Inflector;
use Grav\Common\Language\Language;
use Grav\Common\Page\Page;
use Grav\Common\Page\Pages;
use Grav\Common\Plugin;
use Grav\Common\Uri;
use Grav\Common\Utils;
2015-12-10 12:07:36 +01:00
use Grav\Common\User\User;
use Grav\Plugin\Admin\Admin;
use Grav\Plugin\Admin\Popularity;
use Grav\Plugin\Admin\Themes;
use Grav\Plugin\Admin\AdminController;
2018-05-10 10:14:18 +03:00
use Grav\Plugin\Admin\Twig\AdminTwigExtension;
2017-08-31 12:46:51 -06:00
use Grav\Plugin\Login\Login;
use RocketTheme\Toolbox\Event\Event;
2014-10-01 22:28:16 +03:00
use RocketTheme\Toolbox\Session\Session;
2014-08-05 13:06:38 -07:00
class AdminPlugin extends Plugin
{
2016-01-22 10:42:38 +02:00
public $features = [
'blueprints' => 1000,
];
2014-08-05 13:06:38 -07:00
/**
* @var bool
*/
protected $active = false;
/**
* @var string
*/
protected $template;
2014-09-03 22:22:03 -06:00
/**
* @var string
*/
protected $theme;
2014-08-05 13:06:38 -07:00
/**
* @var string
*/
protected $route;
2016-09-27 18:21:11 +03:00
/**
* @var string
*/
protected $admin_route;
2014-08-05 13:06:38 -07:00
/**
* @var Uri
*/
protected $uri;
/**
* @var Admin
*/
protected $admin;
2014-10-01 22:28:16 +03:00
/**
* @var Session
*/
protected $session;
/**
* @var Popularity
*/
protected $popularity;
2014-10-01 22:28:16 +03:00
/**
* @var string
*/
protected $base;
2016-04-26 12:57:29 -06:00
protected $version;
/**
* @return array
*/
public static function getSubscribedEvents()
{
2016-07-07 18:55:52 +02:00
2017-09-25 17:10:54 -06:00
return [
'onPluginsInitialized' => [
['setup', 100000],
['onPluginsInitialized', 1001]
],
'onPageInitialized' => ['onPageInitialized', 0],
'onShutdown' => ['onShutdown', 1000],
'onFormProcessed' => ['onFormProcessed', 0],
'onAdminDashboard' => ['onAdminDashboard', 0],
'onAdminTools' => ['onAdminTools', 0],
];
2015-12-10 12:07:36 +01:00
}
public function onPageInitialized()
{
$page = $this->grav['page'];
$template = $this->grav['uri']->param('tmpl');
if ($template) {
$page->template($template);
}
}
2015-12-10 11:02:19 -07:00
/**
* If the admin path matches, initialize the Login plugin configuration and set the admin
* as active.
*/
public function setup()
{
// Autoloader
spl_autoload_register(function ($class) {
if (Utils::startsWith($class, 'Grav\Plugin\Admin')) {
2018-05-10 10:14:18 +03:00
require_once __DIR__ .'/classes/' . strtolower(basename(str_replace("\\", '/', $class))) . '.php';
}
});
2015-12-10 11:02:19 -07:00
$route = $this->config->get('plugins.admin.route');
if (!$route) {
return;
}
$this->base = '/' . trim($route, '/');
2016-09-27 18:21:11 +03:00
$this->admin_route = rtrim($this->grav['pages']->base(), '/') . $this->base;
$this->uri = $this->grav['uri'];
2015-12-10 11:02:19 -07:00
2017-08-31 12:46:51 -06:00
$users_exist = Admin::doAnyUsersExist();
2015-12-10 11:02:19 -07:00
// If no users found, go to register
2017-08-31 12:46:51 -06:00
if (!$users_exist) {
if (!$this->isAdminPath()) {
2016-09-27 18:21:11 +03:00
$this->grav->redirect($this->admin_route);
2015-12-10 11:02:19 -07:00
}
$this->template = 'register';
2015-12-10 11:02:19 -07:00
}
// Only activate admin if we're inside the admin path.
if ($this->isAdminPath()) {
2015-12-10 11:02:19 -07:00
$this->active = true;
// Set cache based on admin_cache option
if (method_exists($this->grav['cache'], 'setEnabled')) {
$this->grav['cache']->setEnabled($this->config->get('plugins.admin.cache_enabled'));
}
2015-12-10 11:02:19 -07:00
}
}
2015-12-10 12:07:36 +01:00
/**
* Validate a value. Currently validates
*
* - 'user' for username format and username availability.
* - 'password1' for password format
* - 'password2' for equality to password1
*
2016-07-07 18:55:52 +02:00
* @param string $type The field type
* @param string $value The field value
* @param string $extra Any extra value required
2015-12-10 12:07:36 +01:00
*
2016-01-21 09:46:38 +02:00
* @return bool
2015-12-10 12:07:36 +01:00
*/
protected function validate($type, $value, $extra = '')
{
/** @var Login $login */
$login = $this->grav['login'];
return $login->validateField($type, $value, $extra);
2015-12-10 12:07:36 +01:00
}
/**
* Process the admin registration form.
*
* @param Event $event
* @FIXME: login
2015-12-10 12:07:36 +01:00
*/
public function onFormProcessed(Event $event)
{
$form = $event['form'];
$action = $event['action'];
switch ($action) {
case 'register_admin_user':
2017-08-31 12:46:51 -06:00
if (Admin::doAnyUsersExist()) {
throw new \RuntimeException('A user account already exists, please create an admin account manually.');
}
2015-12-10 12:07:36 +01:00
if (!$this->config->get('plugins.login.enabled')) {
throw new \RuntimeException($this->grav['language']->translate('PLUGIN_LOGIN.PLUGIN_LOGIN_DISABLED'));
}
$data = [];
$username = $form->value('username');
2018-05-10 10:14:18 +03:00
if ($form->value('password1') !== $form->value('password2')) {
2016-07-07 18:55:52 +02:00
$this->grav->fireEvent('onFormValidationError', new Event([
'form' => $form,
2015-12-10 12:07:36 +01:00
'message' => $this->grav['language']->translate('PLUGIN_LOGIN.PASSWORDS_DO_NOT_MATCH')
]));
$event->stopPropagation();
2016-07-07 18:55:52 +02:00
2015-12-10 12:07:36 +01:00
return;
}
2015-12-10 12:07:36 +01:00
$data['password'] = $form->value('password1');
$fields = [
'email',
'fullname',
'title'
];
2016-07-07 18:55:52 +02:00
foreach ($fields as $field) {
2015-12-10 12:07:36 +01:00
// Process value of field if set in the page process.register_user
if (!isset($data[$field]) && $form->value($field)) {
$data[$field] = $form->value($field);
}
}
2018-05-10 10:14:18 +03:00
// Don't store plain text password or username (part of the filename).
unset($data['password1'], $data['password2'], $data['username']);
2015-12-10 12:07:36 +01:00
2015-12-11 10:34:40 -07:00
// Extra lowercase to ensure file is saved lowercase
$username = strtolower($username);
$inflector = new Inflector();
$data['fullname'] = isset($data['fullname']) ? $data['fullname'] : $inflector->titleize($username);
$data['title'] = isset($data['title']) ? $data['title'] : 'Administrator';
2015-12-10 12:07:36 +01:00
$data['state'] = 'enabled';
$data['access'] = ['admin' => ['login' => true, 'super' => true], 'site' => ['login' => true]];
2016-07-07 18:55:52 +02:00
// Create user object and save it
2015-12-10 12:07:36 +01:00
$user = new User($data);
2016-07-07 18:55:52 +02:00
$file = CompiledYamlFile::instance($this->grav['locator']->findResource('user://accounts/' . $username . YAML_EXT,
true, true));
2015-12-10 12:07:36 +01:00
$user->file($file);
$user->save();
$user = User::load($username);
//Login user
$this->grav['session']->user = $user;
unset($this->grav['user']);
$this->grav['user'] = $user;
2017-08-31 12:46:51 -06:00
$user->authenticated = true;
$user->authorized = $user->authorize('site.login');
2015-12-10 12:07:36 +01:00
$messages = $this->grav['messages'];
$messages->add($this->grav['language']->translate('PLUGIN_ADMIN.LOGIN_LOGGED_IN'), 'info');
2016-09-27 18:21:11 +03:00
$this->grav->redirect($this->admin_route);
2015-12-10 12:07:36 +01:00
break;
}
}
/**
2015-07-30 12:20:25 +02:00
* If the admin plugin is set as active, initialize the admin
*/
public function onPluginsInitialized()
{
// Only activate admin if we're inside the admin path.
if ($this->active) {
2016-04-26 12:57:29 -06:00
// Store this version and prefer newer method
if (method_exists($this, 'getBlueprint')) {
$this->version = $this->getBlueprint()->version;
} else {
$this->version = $this->grav['plugins']->get('admin')->blueprints()->version;
}
2016-04-26 12:42:16 -06:00
// Test for correct Grav 1.1 version
if (version_compare(GRAV_VERSION, '1.1.0-beta.1', '<')) {
$messages = $this->grav['messages'];
2016-07-07 18:55:52 +02:00
$messages->add($this->grav['language']->translate(['PLUGIN_ADMIN.NEEDS_GRAV_1_1', GRAV_VERSION]),
'error');
}
// Have a unique Admin-only Cache key
2016-07-07 18:55:52 +02:00
if (method_exists($this->grav['cache'], 'setKey')) {
$cache = $this->grav['cache'];
$cache_key = $cache->getKey();
$cache->setKey($cache_key . '$');
}
2016-04-07 21:01:38 +02:00
// Turn on Twig autoescaping
2018-05-10 10:14:18 +03:00
if (method_exists($this->grav['twig'], 'setAutoescape') && $this->grav['uri']->param('task') !== 'processmarkdown') {
$this->grav['twig']->setAutoescape(true);
}
2015-10-20 10:36:48 +02:00
$this->grav['debugger']->addMessage("Admin Basic");
$this->initializeAdmin();
2014-09-09 14:03:01 -06:00
// Disable Asset pipelining (old method - remove this after Grav is updated)
2016-07-07 18:55:52 +02:00
if (!method_exists($this->grav['assets'], 'setJsPipeline')) {
$this->config->set('system.assets.css_pipeline', false);
$this->config->set('system.assets.js_pipeline', false);
}
// Replace themes service with admin.
2016-01-28 14:38:01 +01:00
$this->grav['themes'] = function () {
return new Themes($this->grav);
};
2014-08-05 13:06:38 -07:00
}
2014-09-09 14:03:01 -06:00
// We need popularity no matter what
$this->popularity = new Popularity();
// Fire even to register permissions from other plugins
$this->grav->fireEvent('onAdminRegisterPermissions', new Event(['admin' => $this->admin]));
2014-08-05 13:06:38 -07:00
}
2016-07-07 18:55:52 +02:00
protected function initializeController($task, $post)
{
$controller = new AdminController();
$controller->initialize($this->grav, $this->template, $task, $this->route, $post);
$controller->execute();
$controller->redirect();
}
2014-08-05 13:06:38 -07:00
/**
* Sets longer path to the home page allowing us to have list of pages when we enter to pages section.
*/
public function onPagesInitialized()
2014-08-05 13:06:38 -07:00
{
$this->session = $this->grav['session'];
2014-08-05 13:06:38 -07:00
// Set original route for the home page.
$home = '/' . trim($this->config->get('system.home.alias'), '/');
2014-10-06 19:03:57 -06:00
// set the default if not set before
$this->session->expert = $this->session->expert ?: false;
2014-10-06 19:03:57 -06:00
// set session variable if it's passed via the url
2018-05-10 10:14:18 +03:00
if ($this->uri->param('mode') === 'expert') {
$this->session->expert = true;
2018-05-10 10:14:18 +03:00
} elseif ($this->uri->param('mode') === 'normal') {
$this->session->expert = false;
}
2014-08-05 13:06:38 -07:00
/** @var Pages $pages */
$pages = $this->grav['pages'];
$this->grav['admin']->routes = $pages->routes();
// Remove default route from routes.
if (isset($this->grav['admin']->routes['/'])) {
unset($this->grav['admin']->routes['/']);
}
$page = $pages->dispatch('/', true);
// If page is null, the default page does not exist, and we cannot route to it
if ($page) {
$page->route($home);
}
2014-08-05 13:06:38 -07:00
// Make local copy of POST.
2016-07-07 18:55:52 +02:00
$post = !empty($_POST) ? $_POST : [];
2014-08-05 13:06:38 -07:00
// Handle tasks.
2014-09-22 15:49:53 -06:00
$this->admin->task = $task = !empty($post['task']) ? $post['task'] : $this->uri->param('task');
2014-08-05 13:06:38 -07:00
if ($task) {
$this->initializeController($task, $post);
2018-05-10 10:14:18 +03:00
} elseif ($this->template === 'logs' && $this->route) {
2014-08-05 13:06:38 -07:00
// Display RAW error message.
echo $this->admin->logEntry();
exit();
}
$self = $this;
2014-08-05 13:06:38 -07:00
2015-12-09 21:37:34 -07:00
// make sure page is not frozen!
unset($this->grav['page']);
$this->admin->pagesCount();
// Replace page service with admin.
$this->grav['page'] = function () use ($self) {
$page = new Page;
$page->expires(0);
2017-04-11 09:47:12 +02:00
// First look in the pages provided by the Admin plugin itself
if (file_exists(__DIR__ . "/pages/admin/{$self->template}.md")) {
$page->init(new \SplFileInfo(__DIR__ . "/pages/admin/{$self->template}.md"));
$page->slug(basename($self->template));
return $page;
}
2017-04-11 09:47:12 +02:00
// If not provided by Admin, lookup pages added by other plugins
$plugins = $this->grav['plugins'];
$locator = $this->grav['locator'];
2016-07-07 18:55:52 +02:00
foreach ($plugins as $plugin) {
if ($this->config->get("plugins.{$plugin->name}.enabled") !== true) {
continue;
}
2016-07-07 18:55:52 +02:00
$path = $locator->findResource("user://plugins/{$plugin->name}/admin/pages/{$self->template}.md");
2015-10-26 21:30:33 +01:00
if ($path) {
2015-10-26 21:30:33 +01:00
$page->init(new \SplFileInfo($path));
$page->slug(basename($self->template));
2016-07-07 18:55:52 +02:00
2015-10-26 21:30:33 +01:00
return $page;
}
}
2016-01-21 09:46:38 +02:00
return null;
};
if (empty($this->grav['page'])) {
if ($this->grav['user']->authenticated) {
$event = $this->grav->fireEvent('onPageNotFound');
if (isset($event->page)) {
unset($this->grav['page']);
$this->grav['page'] = $event->page;
} else {
throw new \RuntimeException('Page Not Found', 404);
}
} else {
2016-09-27 18:21:11 +03:00
$this->grav->redirect($this->admin_route);
}
}
// Explicitly set a timestamp on assets
2016-07-07 18:55:52 +02:00
$this->grav['assets']->setTimestamp(substr(md5(GRAV_VERSION . $this->grav['config']->checksum()), 0, 10));
2014-08-05 13:06:38 -07:00
}
2016-01-10 17:17:04 +01:00
/**
* Handles initializing the assets
*/
public function onAssetsInitialized()
{
// Disable Asset pipelining
$assets = $this->grav['assets'];
$assets->setJsPipeline(false);
$assets->setCssPipeline(false);
}
2014-08-05 13:06:38 -07:00
/**
* Add twig paths to plugin templates.
*/
public function onTwigTemplatePaths()
2014-08-05 13:06:38 -07:00
{
$twig_paths = [];
$this->grav->fireEvent('onAdminTwigTemplatePaths', new Event(['paths' => &$twig_paths]));
$twig_paths[] = __DIR__ . '/themes/' . $this->theme . '/templates';
$this->grav['twig']->twig_paths = $twig_paths;
2014-08-05 13:06:38 -07:00
}
/**
* Set all twig variables for generating output.
*/
public function onTwigSiteVariables()
2014-08-05 13:06:38 -07:00
{
$twig = $this->grav['twig'];
2017-04-13 14:50:27 -06:00
$page = $this->grav['page'];
2014-08-05 13:06:38 -07:00
$twig->twig_vars['location'] = $this->template;
$twig->twig_vars['base_url_relative_frontend'] = $twig->twig_vars['base_url_relative'] ?: '/';
2016-09-27 18:21:11 +03:00
$twig->twig_vars['admin_route'] = trim($this->admin_route, '/');
2016-07-07 18:55:52 +02:00
$twig->twig_vars['base_url_relative'] = $twig->twig_vars['base_url_simple'] . '/' . $twig->twig_vars['admin_route'];
2016-07-15 17:39:13 +02:00
$theme_url = '/' . ltrim($this->grav['locator']->findResource('plugin://admin/themes/' . $this->theme,
false), '/');
$twig->twig_vars['theme_url'] = $theme_url;
2014-08-29 11:59:43 +03:00
$twig->twig_vars['base_url'] = $twig->twig_vars['base_url_relative'];
$twig->twig_vars['base_path'] = GRAV_ROOT;
2014-08-05 13:06:38 -07:00
$twig->twig_vars['admin'] = $this->admin;
2016-04-26 12:57:29 -06:00
$twig->twig_vars['admin_version'] = $this->version;
2014-08-05 13:06:38 -07:00
$fa_icons_file = CompiledYamlFile::instance($this->grav['locator']->findResource('plugin://admin/themes/grav/templates/forms/fields/iconpicker/icons' . YAML_EXT));
$fa_icons = $fa_icons_file->content();
$fa_icons = array_map(function ($icon) {
//only pick used values
return ['id' => $icon['id'], 'unicode' => $icon['unicode']];
}, $fa_icons['icons']);
$twig->twig_vars['fa_icons'] = $fa_icons;
2017-04-13 14:50:27 -06:00
// add form if it exists in the page
$header = $page->header();
if (isset($header->form)) {
// preserve form validation
if (!isset($twig->twig_vars['form'])) {
$twig->twig_vars['form'] = new Form($page);
}
2017-04-13 14:50:27 -06:00
}
// Gather Plugin-hooked nav items
2015-10-26 21:30:33 +01:00
$this->grav->fireEvent('onAdminMenu');
2014-08-05 13:06:38 -07:00
switch ($this->template) {
case 'dashboard':
$twig->twig_vars['popularity'] = $this->popularity;
// Gather Plugin-hooked dashboard items
$this->grav->fireEvent('onAdminDashboard');
2014-08-05 13:06:38 -07:00
break;
}
2017-12-01 16:08:52 -07:00
$flashData = $this->grav['session']->getFlashCookieObject(Admin::TMP_COOKIE_NAME);
if (isset($flashData->message)) {
$this->grav['messages']->add($flashData->message, $flashData->status);
}
2014-08-05 13:06:38 -07:00
}
2014-09-03 22:22:03 -06:00
2016-01-10 17:17:04 +01:00
/**
* Handles the shutdown
*/
public function onShutdown()
{
if ($this->active) {
//only activate when Admin is active
if ($this->admin->shouldLoadAdditionalFilesInBackground()) {
$this->admin->loadAdditionalFilesInBackground();
}
} else {
//if popularity is enabled, track non-admin hits
if ($this->config->get('plugins.admin.popularity.enabled')) {
$this->popularity->trackHit();
}
}
}
/**
* Get list of form field types specified in this plugin. Only special types needs to be listed.
*
* @return array
*/
public function getFormFieldTypes()
{
return [
2016-07-07 18:55:52 +02:00
'column' => [
2016-03-03 20:59:59 +02:00
'input@' => false
],
2016-07-07 18:55:52 +02:00
'columns' => [
2016-03-03 20:59:59 +02:00
'input@' => false
],
'fieldset' => [
2016-03-03 20:59:59 +02:00
'input@' => false
],
2016-07-07 18:55:52 +02:00
'section' => [
2016-03-03 20:59:59 +02:00
'input@' => false
],
2016-07-07 18:55:52 +02:00
'tab' => [
2016-03-03 20:59:59 +02:00
'input@' => false
],
2016-07-07 18:55:52 +02:00
'tabs' => [
2016-03-03 20:59:59 +02:00
'input@' => false
2016-03-10 19:56:38 +02:00
],
2016-07-07 18:55:52 +02:00
'key' => [
2016-03-15 14:38:17 +02:00
'input@' => false
],
2016-07-07 18:55:52 +02:00
'list' => [
2016-03-10 19:56:38 +02:00
'array' => true
[WIP] Ajax Files Upload (#748) * Reworked the `file` field. All files get uploaded via Ajax and are stored upon Save This improves the Save task tremendously as now there is no longer the need of waiting for the files to finish uploading. Fully backward compatible, `file` field now includes also a `limit` and `filesize` option in the blueprints. The former determines how many files are allowed to be uploaded when in combination with `multiple: true` (default: 10), the latter determines the file size limit (in MB) allowed for each file (default: 5MB) * Added support for `accept: [‘*’]` to allow any file type * Minor tweaks in the comments and messages * Delete any orphan file when discarding the uploaded files session * Minor optimization * Fixed issue with `_json` elements where nested fields merging would get stored in an unexpected way * Potential fix for wrong order of value in Datetime * Fixed nested fields for files * Fixed tmp streams * Minor cleanup * Update JSON data when removing a file. Implemented task to remove files that haven’t been saved yet, from the flash object session * Ensure temporary files are deleted when removing un-saved files from the flash object session * Fixed wrong reference of HTML file field when clicking on the drop zone area to pick a file * Added JSON template for pages * fix a CSS issue in page order * More CSS fixes * Trigger file field mutation when adding or removing a file * Recompiled JS * Removed twig templates that are no longer needed * Fixed issue with nested header fields in a page, not properly merging data * [internal] Fixed issue with collections not capable of handling both param and dot notations at the same time * Reorganized FileField structure to be more consistent with the other fields * Added support for dynamically created file fields (ie, autoinitialization on new lists items) * Added translationable strings for file uploads errors * Added translasions for all Dropzone available strings * Changed default values
2016-08-29 11:12:09 -07:00
],
'file' => [
'array' => true
]
];
}
2015-07-30 12:20:25 +02:00
/**
* Initialize the admin.
*
* @throws \RuntimeException
*/
2014-09-03 22:22:03 -06:00
protected function initializeAdmin()
{
$this->enable([
2016-07-07 18:55:52 +02:00
'onTwigExtensions' => ['onTwigExtensions', 1000],
'onPagesInitialized' => ['onPagesInitialized', 1000],
'onTwigTemplatePaths' => ['onTwigTemplatePaths', 1000],
'onTwigSiteVariables' => ['onTwigSiteVariables', 1000],
'onAssetsInitialized' => ['onAssetsInitialized', 1000],
'onAdminRegisterPermissions' => ['onAdminRegisterPermissions', 0],
'onOutputGenerated' => ['onOutputGenerated', 0],
'onAdminAfterSave' => ['onAdminAfterSave', 0],
]);
2014-09-03 22:22:03 -06:00
// Autoload classes
require_once __DIR__ . '/vendor/autoload.php';
2015-07-27 12:56:16 -06:00
// Check for required plugins
2016-07-07 18:55:52 +02:00
if (!$this->grav['config']->get('plugins.login.enabled') || !$this->grav['config']->get('plugins.form.enabled') || !$this->grav['config']->get('plugins.email.enabled')) {
2015-07-27 12:56:16 -06:00
throw new \RuntimeException('One of the required plugins is missing or not enabled');
}
// Initialize Admin Language if needed
/** @var Language $language */
$language = $this->grav['language'];
if ($language->enabled() && empty($this->grav['session']->admin_lang)) {
$this->grav['session']->admin_lang = $language->getLanguage();
}
// Decide admin template and route.
$path = trim(substr($this->uri->route(), strlen($this->base)), '/');
2015-12-10 11:02:19 -07:00
if (empty($this->template)) {
$this->template = 'dashboard';
}
// Can't access path directly...
2018-05-10 10:14:18 +03:00
if ($path && $path !== 'register') {
$array = explode('/', $path, 2);
$this->template = array_shift($array);
$this->route = array_shift($array);
}
2014-09-03 22:22:03 -06:00
// Initialize admin class.
2016-09-27 18:21:11 +03:00
$this->admin = new Admin($this->grav, $this->admin_route, $this->template, $this->route);
2016-02-04 20:59:08 +01:00
// And store the class into DI container.
$this->grav['admin'] = $this->admin;
// Double check we have system.yaml, site.yaml etc
$config_path = $this->grav['locator']->findResource('user://config');
foreach ($this->admin->configurations() as $config_file) {
$config_file = "{$config_path}/{$config_file}.yaml";
if (!file_exists($config_file)) {
touch($config_file);
}
}
// Get theme for admin
$this->theme = $this->config->get('plugins.admin.theme', 'grav');
$assets = $this->grav['assets'];
2016-07-07 18:55:52 +02:00
$translations = 'this.GravAdmin = this.GravAdmin || {}; if (!this.GravAdmin.translations) this.GravAdmin.translations = {}; ' . PHP_EOL . 'this.GravAdmin.translations.PLUGIN_ADMIN = {';
// Enable language translations
$translations_actual_state = $this->config->get('system.languages.translations');
$this->config->set('system.languages.translations', true);
2016-07-07 18:55:52 +02:00
$strings = [
'EVERYTHING_UP_TO_DATE',
'UPDATES_ARE_AVAILABLE',
'IS_AVAILABLE_FOR_UPDATE',
'AND',
'IS_NOW_AVAILABLE',
'CURRENT',
'UPDATE_GRAV_NOW',
'TASK_COMPLETED',
'UPDATE',
'UPDATING_PLEASE_WAIT',
'GRAV_SYMBOLICALLY_LINKED',
'OF_YOUR',
'OF_THIS',
'HAVE_AN_UPDATE_AVAILABLE',
'UPDATE_AVAILABLE',
'UPDATES_AVAILABLE',
'FULLY_UPDATED',
2015-10-21 19:54:10 +02:00
'DAYS',
'PAGE_MODES',
'PAGE_TYPES',
2016-02-01 11:27:34 -08:00
'ACCESS_LEVELS',
2016-02-01 16:34:50 -08:00
'NOTHING_TO_SAVE',
'FILE_UNSUPPORTED',
'FILE_ERROR_ADD',
'FILE_ERROR_UPLOAD',
'DROP_FILES_HERE_TO_UPLOAD',
'DELETE',
'UNSET',
'INSERT',
'METADATA',
'VIEW',
'UNDO',
'REDO',
'HEADERS',
'BOLD',
'ITALIC',
'STRIKETHROUGH',
'SUMMARY_DELIMITER',
'LINK',
'IMAGE',
'BLOCKQUOTE',
'UNORDERED_LIST',
'ORDERED_LIST',
'EDITOR',
'PREVIEW',
2016-05-06 18:17:26 +02:00
'FULLSCREEN',
'MODULAR',
'NON_MODULAR',
'VISIBLE',
'NON_VISIBLE',
'ROUTABLE',
'NON_ROUTABLE',
'PUBLISHED',
'NON_PUBLISHED',
'PLUGINS',
'THEMES',
'ALL',
'FROM',
[WIP] Ajax Files Upload (#748) * Reworked the `file` field. All files get uploaded via Ajax and are stored upon Save This improves the Save task tremendously as now there is no longer the need of waiting for the files to finish uploading. Fully backward compatible, `file` field now includes also a `limit` and `filesize` option in the blueprints. The former determines how many files are allowed to be uploaded when in combination with `multiple: true` (default: 10), the latter determines the file size limit (in MB) allowed for each file (default: 5MB) * Added support for `accept: [‘*’]` to allow any file type * Minor tweaks in the comments and messages * Delete any orphan file when discarding the uploaded files session * Minor optimization * Fixed issue with `_json` elements where nested fields merging would get stored in an unexpected way * Potential fix for wrong order of value in Datetime * Fixed nested fields for files * Fixed tmp streams * Minor cleanup * Update JSON data when removing a file. Implemented task to remove files that haven’t been saved yet, from the flash object session * Ensure temporary files are deleted when removing un-saved files from the flash object session * Fixed wrong reference of HTML file field when clicking on the drop zone area to pick a file * Added JSON template for pages * fix a CSS issue in page order * More CSS fixes * Trigger file field mutation when adding or removing a file * Recompiled JS * Removed twig templates that are no longer needed * Fixed issue with nested header fields in a page, not properly merging data * [internal] Fixed issue with collections not capable of handling both param and dot notations at the same time * Reorganized FileField structure to be more consistent with the other fields * Added support for dynamically created file fields (ie, autoinitialization on new lists items) * Added translationable strings for file uploads errors * Added translasions for all Dropzone available strings * Changed default values
2016-08-29 11:12:09 -07:00
'TO',
'DROPZONE_CANCEL_UPLOAD',
'DROPZONE_CANCEL_UPLOAD_CONFIRMATION',
'DROPZONE_DEFAULT_MESSAGE',
'DROPZONE_FALLBACK_MESSAGE',
'DROPZONE_FALLBACK_TEXT',
'DROPZONE_FILE_TOO_BIG',
'DROPZONE_INVALID_FILE_TYPE',
'DROPZONE_MAX_FILES_EXCEEDED',
'DROPZONE_REMOVE_FILE',
'DROPZONE_RESPONSE_ERROR'
2015-10-21 19:54:10 +02:00
];
2016-07-07 18:55:52 +02:00
foreach ($strings as $string) {
2016-02-01 11:27:34 -08:00
$separator = (end($strings) === $string) ? '' : ',';
$translations .= '"' . $string . '": "' . htmlspecialchars($this->admin->translate('PLUGIN_ADMIN.' . $string)) . '"' . $separator;
}
2016-02-01 11:27:34 -08:00
$translations .= '};';
$translations .= 'this.GravAdmin.translations.PLUGIN_FORM = {';
$strings = ['RESOLUTION_MIN', 'RESOLUTION_MAX'];
foreach ($strings as $string) {
$separator = (end($strings) === $string) ? '' : ',';
$translations .= '"' . $string . '": "' . $this->admin->translate('PLUGIN_FORM.' . $string) . '"' . $separator;
}
$translations .= '};';
// set the actual translations state back
$this->config->set('system.languages.translations', $translations_actual_state);
$assets->addInlineJs($translations);
2014-09-03 22:22:03 -06:00
}
/**
2016-01-10 17:17:04 +01:00
* Add the Admin Twig Extensions
*/
public function onTwigExtensions()
{
2018-05-10 10:14:18 +03:00
require_once __DIR__ . '/classes/Twig/AdminTwigExtension.php';
$this->grav['twig']->twig->addExtension(new AdminTwigExtension);
}
2015-12-10 12:08:06 -07:00
2016-01-10 17:17:04 +01:00
/**
* Check if the current route is under the admin path
*
* @return bool
*/
public function isAdminPath()
{
2018-05-10 10:14:18 +03:00
$route = $this->uri->route();
2016-07-07 18:55:52 +02:00
2018-05-10 10:14:18 +03:00
return $route === $this->base || 0 === strpos($route, $this->base . '/');
}
public function onAdminAfterSave(Event $event)
{
// Special case to redirect after changing the admin route to avoid 'breaking'
$obj = $event['object'];
2018-05-10 10:14:18 +03:00
if (null !== $obj) {
$blueprint = $obj->blueprints()->getFilename();
2018-05-10 10:14:18 +03:00
if ($blueprint === 'admin/blueprints' && isset($obj->route) && $this->admin_route !== $obj->route) {
$redirect = preg_replace('/^' . str_replace('/','\/',$this->admin_route) . '/',$obj->route,$this->uri->path());
$this->grav->redirect($redirect);
}
}
}
/**
* Provide the tools for the Tools page, currently only direct install
*
* @return Event
*/
public function onAdminTools(Event $event)
{
$event['tools'] = array_merge($event['tools'], [$this->grav['language']->translate('PLUGIN_ADMIN.DIRECT_INSTALL')]);
return $event;
}
public function onAdminDashboard()
{
$this->grav['twig']->plugins_hooked_dashboard_widgets_top[] = ['template' => 'dashboard-maintenance'];
$this->grav['twig']->plugins_hooked_dashboard_widgets_top[] = ['template' => 'dashboard-statistics'];
$this->grav['twig']->plugins_hooked_dashboard_widgets_top[] = ['template' => 'dashboard-notifications'];
$this->grav['twig']->plugins_hooked_dashboard_widgets_top[] = ['template' => 'dashboard-feed'];
$this->grav['twig']->plugins_hooked_dashboard_widgets_main[] = ['template' => 'dashboard-pages'];
}
public function onOutputGenerated()
{
// Clear flash objects for previously uploaded files
// whenever the user switches page / reloads
// ignoring any JSON / extension call
2018-05-10 10:14:18 +03:00
if ($this->admin->task !== 'save' && empty($this->uri->extension())) {
// Discard any previously uploaded files session.
// and if there were any uploaded file, remove them from the filesystem
if ($flash = $this->session->getFlashObject('files-upload')) {
$flash = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($flash));
foreach ($flash as $key => $value) {
if ($key !== 'tmp_name') {
continue;
}
@unlink($value);
}
}
}
}
/**
* Initial stab at registering permissions (WIP)
*
* @param Event $e
*/
public function onAdminRegisterPermissions(Event $e)
{
$admin = $e['admin'];
$permissions = [
2016-07-07 18:55:52 +02:00
'admin.super' => 'boolean',
'admin.login' => 'boolean',
'admin.cache' => 'boolean',
'admin.configuration' => 'boolean',
'admin.configuration_system' => 'boolean',
'admin.configuration_site' => 'boolean',
'admin.configuration_media' => 'boolean',
'admin.configuration_info' => 'boolean',
2016-07-07 18:55:52 +02:00
'admin.settings' => 'boolean',
'admin.pages' => 'boolean',
'admin.maintenance' => 'boolean',
'admin.statistics' => 'boolean',
'admin.plugins' => 'boolean',
'admin.themes' => 'boolean',
'admin.users' => 'boolean',
];
$admin->addPermissions($permissions);
}
/**
* Helper function to replace Pages::Types()
* and to provide an event to manipulate the data
*
* Dispatches 'onAdminPageTypes' event
* with 'types' data member which is a
* reference to the data
*/
public static function pagesTypes()
{
$types = Pages::types();
// First filter by configuration
$hideTypes = Grav::instance()['config']->get('plugins.admin.hide_page_types', []);
2018-05-10 10:14:18 +03:00
foreach ((array) $hideTypes as $type) {
unset($types[$type]);
}
// Allow manipulating of the data by event
$e = new Event(['types' => &$types]);
Grav::instance()->fireEvent('onAdminPageTypes', $e);
return $types;
}
/**
* Helper function to replace Pages::modularTypes()
* and to provide an event to manipulate the data
*
* Dispatches 'onAdminModularPageTypes' event
* with 'types' data member which is a
* reference to the data
*/
public static function pagesModularTypes()
{
$types = Pages::modularTypes();
// First filter by configuration
2018-05-10 10:14:18 +03:00
$hideTypes = (array) Grav::instance()['config']->get('plugins.admin.hide_modular_page_types', []);
foreach ($hideTypes as $type) {
unset($types[$type]);
}
// Allow manipulating of the data by event
$e = new Event(['types' => &$types]);
Grav::instance()->fireEvent('onAdminModularPageTypes', $e);
return $types;
}
2014-08-05 13:06:38 -07:00
}