mirror of
https://github.com/getgrav/grav-plugin-admin.git
synced 2025-11-02 03:16:11 +01:00
Feature/admin fragmentation (#856)
* Separated Admin Controller into a generic and extendable Base controller. Added Autoload for properly loading classes * Implemented custom class loader to force lowercase * Removed composer autoloader for classes * Updates * Ability to pass custom upload URL for files * Added new onAdminCanSave event for 3rd party plugins * Moved files upload GC in onOutputGenerated event * Cleanup * Moved autoloader so it is always registering * Fixed onOutputGenerated event location * Moved `taskRemoveFileFromBlueprint`, `taskRemoveMedia `, `canEditMedia` methods to admin base controller * Allow to globally define `blueprint_type` and `file_url_remove` for the file field * Moved `isMultilang()` into base controller * Properly generate thumbnails in proportions for file fields * Simplified execute restrictions with blacklist
This commit is contained in:
70
admin.php
70
admin.php
@@ -10,8 +10,13 @@ use Grav\Common\Page\Page;
|
|||||||
use Grav\Common\Page\Pages;
|
use Grav\Common\Page\Pages;
|
||||||
use Grav\Common\Plugin;
|
use Grav\Common\Plugin;
|
||||||
use Grav\Common\Uri;
|
use Grav\Common\Uri;
|
||||||
|
use Grav\Common\Utils;
|
||||||
use Grav\Common\User\User;
|
use Grav\Common\User\User;
|
||||||
use RocketTheme\Toolbox\File\File;
|
use Grav\Plugin\Admin\Admin;
|
||||||
|
use Grav\Plugin\Admin\AdminTwigExtension;
|
||||||
|
use Grav\Plugin\Admin\Popularity;
|
||||||
|
use Grav\Plugin\Admin\Themes;
|
||||||
|
use Grav\Plugin\Admin\AdminController;
|
||||||
use RocketTheme\Toolbox\Event\Event;
|
use RocketTheme\Toolbox\Event\Event;
|
||||||
use RocketTheme\Toolbox\Session\Session;
|
use RocketTheme\Toolbox\Session\Session;
|
||||||
|
|
||||||
@@ -96,6 +101,13 @@ class AdminPlugin extends Plugin
|
|||||||
*/
|
*/
|
||||||
public function setup()
|
public function setup()
|
||||||
{
|
{
|
||||||
|
// Autoloader
|
||||||
|
spl_autoload_register(function ($class) {
|
||||||
|
if (Utils::startsWith($class, 'Grav\Plugin\Admin')) {
|
||||||
|
require_once __DIR__ .'/classes/' . strtolower(basename(str_replace("\\", "/", $class))) . '.php';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$route = $this->config->get('plugins.admin.route');
|
$route = $this->config->get('plugins.admin.route');
|
||||||
if (!$route) {
|
if (!$route) {
|
||||||
return;
|
return;
|
||||||
@@ -303,14 +315,11 @@ class AdminPlugin extends Plugin
|
|||||||
|
|
||||||
// Replace themes service with admin.
|
// Replace themes service with admin.
|
||||||
$this->grav['themes'] = function () {
|
$this->grav['themes'] = function () {
|
||||||
require_once __DIR__ . '/classes/themes.php';
|
|
||||||
|
|
||||||
return new Themes($this->grav);
|
return new Themes($this->grav);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need popularity no matter what
|
// We need popularity no matter what
|
||||||
require_once __DIR__ . '/classes/popularity.php';
|
|
||||||
$this->popularity = new Popularity();
|
$this->popularity = new Popularity();
|
||||||
|
|
||||||
// Fire even to register permissions from other plugins
|
// Fire even to register permissions from other plugins
|
||||||
@@ -319,8 +328,8 @@ class AdminPlugin extends Plugin
|
|||||||
|
|
||||||
protected function initializeController($task, $post)
|
protected function initializeController($task, $post)
|
||||||
{
|
{
|
||||||
require_once __DIR__ . '/classes/controller.php';
|
$controller = new AdminController();
|
||||||
$controller = new AdminController($this->grav, $this->template, $task, $this->route, $post);
|
$controller->initialize($this->grav, $this->template, $task, $this->route, $post);
|
||||||
$controller->execute();
|
$controller->execute();
|
||||||
$controller->redirect();
|
$controller->redirect();
|
||||||
}
|
}
|
||||||
@@ -375,23 +384,6 @@ class AdminPlugin extends Plugin
|
|||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear flash objects for previously uploaded files
|
|
||||||
// whenever the user switches page / reloads
|
|
||||||
// ignoring any JSON / extension call
|
|
||||||
if (is_null($this->uri->extension()) && $task !== 'save') {
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$self = $this;
|
$self = $this;
|
||||||
|
|
||||||
// make sure page is not frozen!
|
// make sure page is not frozen!
|
||||||
@@ -633,17 +625,12 @@ class AdminPlugin extends Plugin
|
|||||||
'onAssetsInitialized' => ['onAssetsInitialized', 1000],
|
'onAssetsInitialized' => ['onAssetsInitialized', 1000],
|
||||||
'onTask.GPM' => ['onTaskGPM', 0],
|
'onTask.GPM' => ['onTaskGPM', 0],
|
||||||
'onAdminRegisterPermissions' => ['onAdminRegisterPermissions', 0],
|
'onAdminRegisterPermissions' => ['onAdminRegisterPermissions', 0],
|
||||||
|
'onOutputGenerated' => ['onOutputGenerated', 0],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Initialize admin class.
|
|
||||||
require_once __DIR__ . '/classes/admin.php';
|
|
||||||
|
|
||||||
// Autoload classes
|
// Autoload classes
|
||||||
$autoload = __DIR__ . '/vendor/autoload.php';
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
if (!is_file($autoload)) {
|
|
||||||
throw new \Exception('Admin Plugin failed to load. Composer dependencies not met.');
|
|
||||||
}
|
|
||||||
require_once $autoload;
|
|
||||||
|
|
||||||
// Check for required plugins
|
// Check for required plugins
|
||||||
if (!$this->grav['config']->get('plugins.login.enabled') || !$this->grav['config']->get('plugins.form.enabled') || !$this->grav['config']->get('plugins.email.enabled')) {
|
if (!$this->grav['config']->get('plugins.login.enabled') || !$this->grav['config']->get('plugins.form.enabled') || !$this->grav['config']->get('plugins.email.enabled')) {
|
||||||
@@ -671,6 +658,7 @@ class AdminPlugin extends Plugin
|
|||||||
$this->route = array_shift($array);
|
$this->route = array_shift($array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize admin class.
|
||||||
$this->admin = new Admin($this->grav, $this->admin_route, $this->template, $this->route);
|
$this->admin = new Admin($this->grav, $this->admin_route, $this->template, $this->route);
|
||||||
|
|
||||||
|
|
||||||
@@ -812,6 +800,26 @@ class AdminPlugin extends Plugin
|
|||||||
$this->grav['twig']->plugins_hooked_dashboard_widgets_main[] = ['template' => 'dashboard-pages'];
|
$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
|
||||||
|
if (is_null($this->uri->extension()) && $this->admin->task !== 'save') {
|
||||||
|
// 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)
|
* Initial stab at registering permissions (WIP)
|
||||||
*
|
*
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
929
classes/adminbasecontroller.php
Normal file
929
classes/adminbasecontroller.php
Normal file
@@ -0,0 +1,929 @@
|
|||||||
|
<?php
|
||||||
|
namespace Grav\Plugin\Admin;
|
||||||
|
|
||||||
|
use Grav\Common\Config\Config;
|
||||||
|
use Grav\Common\Filesystem\Folder;
|
||||||
|
use Grav\Common\Grav;
|
||||||
|
use Grav\Common\Page\Media;
|
||||||
|
use Grav\Common\Utils;
|
||||||
|
use RocketTheme\Toolbox\Event\Event;
|
||||||
|
use RocketTheme\Toolbox\File\File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AdminController
|
||||||
|
*
|
||||||
|
* @package Grav\Plugin
|
||||||
|
*/
|
||||||
|
class AdminBaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Grav
|
||||||
|
*/
|
||||||
|
public $grav;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $view;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $route;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $post;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array|null
|
||||||
|
*/
|
||||||
|
public $data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Grav\Common\Uri
|
||||||
|
*/
|
||||||
|
protected $uri;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Admin
|
||||||
|
*/
|
||||||
|
protected $admin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $redirect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $redirectCode;
|
||||||
|
|
||||||
|
protected $upload_errors = [
|
||||||
|
0 => "There is no error, the file uploaded with success",
|
||||||
|
1 => "The uploaded file exceeds the max upload size",
|
||||||
|
2 => "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML",
|
||||||
|
3 => "The uploaded file was only partially uploaded",
|
||||||
|
4 => "No file was uploaded",
|
||||||
|
6 => "Missing a temporary folder",
|
||||||
|
7 => "Failed to write file to disk",
|
||||||
|
8 => "A PHP extension stopped the file upload"
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
public $blacklist_views = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a task.
|
||||||
|
*
|
||||||
|
* @return bool True if the action was performed successfully.
|
||||||
|
*/
|
||||||
|
public function execute()
|
||||||
|
{
|
||||||
|
if (in_array($this->view, $this->blacklist_views)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->validateNonce()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$method = 'task' . ucfirst($this->task);
|
||||||
|
|
||||||
|
if (method_exists($this, $method)) {
|
||||||
|
try {
|
||||||
|
$success = call_user_func([$this, $method]);
|
||||||
|
} catch (\RuntimeException $e) {
|
||||||
|
$success = true;
|
||||||
|
$this->admin->setMessage($e->getMessage(), 'error');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$success = $this->grav->fireEvent('onAdminTaskExecute', new Event(['controller' => $this, 'method' => $method]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab redirect parameter.
|
||||||
|
$redirect = isset($this->post['_redirect']) ? $this->post['_redirect'] : null;
|
||||||
|
unset($this->post['_redirect']);
|
||||||
|
|
||||||
|
// Redirect if requested.
|
||||||
|
if ($redirect) {
|
||||||
|
$this->setRedirect($redirect);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function validateNonce()
|
||||||
|
{
|
||||||
|
if (method_exists('Grav\Common\Utils', 'getNonce')) {
|
||||||
|
if (strtolower($_SERVER['REQUEST_METHOD']) == 'post') {
|
||||||
|
if (isset($this->post['admin-nonce'])) {
|
||||||
|
$nonce = $this->post['admin-nonce'];
|
||||||
|
} else {
|
||||||
|
$nonce = $this->grav['uri']->param('admin-nonce');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$nonce || !Utils::verifyNonce($nonce, 'admin-form')) {
|
||||||
|
if ($this->task == 'addmedia') {
|
||||||
|
|
||||||
|
$message = sprintf($this->admin->translate('PLUGIN_ADMIN.FILE_TOO_LARGE', null),
|
||||||
|
ini_get('post_max_size'));
|
||||||
|
|
||||||
|
//In this case it's more likely that the image is too big than POST can handle. Show message
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => $message
|
||||||
|
];
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->admin->setMessage($this->admin->translate('PLUGIN_ADMIN.INVALID_SECURITY_TOKEN'), 'error');
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => $this->admin->translate('PLUGIN_ADMIN.INVALID_SECURITY_TOKEN')
|
||||||
|
];
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
unset($this->post['admin-nonce']);
|
||||||
|
} else {
|
||||||
|
if ($this->task == 'logout') {
|
||||||
|
$nonce = $this->grav['uri']->param('logout-nonce');
|
||||||
|
if (!isset($nonce) || !Utils::verifyNonce($nonce, 'logout-form')) {
|
||||||
|
$this->admin->setMessage($this->admin->translate('PLUGIN_ADMIN.INVALID_SECURITY_TOKEN'),
|
||||||
|
'error');
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => $this->admin->translate('PLUGIN_ADMIN.INVALID_SECURITY_TOKEN')
|
||||||
|
];
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$nonce = $this->grav['uri']->param('admin-nonce');
|
||||||
|
if (!isset($nonce) || !Utils::verifyNonce($nonce, 'admin-form')) {
|
||||||
|
$this->admin->setMessage($this->admin->translate('PLUGIN_ADMIN.INVALID_SECURITY_TOKEN'),
|
||||||
|
'error');
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => $this->admin->translate('PLUGIN_ADMIN.INVALID_SECURITY_TOKEN')
|
||||||
|
];
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the page redirect.
|
||||||
|
*
|
||||||
|
* @param string $path The path to redirect to
|
||||||
|
* @param int $code The HTTP redirect code
|
||||||
|
*/
|
||||||
|
public function setRedirect($path, $code = 303)
|
||||||
|
{
|
||||||
|
$this->redirect = $path;
|
||||||
|
$this->redirectCode = $code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles ajax upload for files.
|
||||||
|
* Stores in a flash object the temporary file and deals with potential file errors.
|
||||||
|
*
|
||||||
|
* @return bool True if the action was performed.
|
||||||
|
*/
|
||||||
|
public function taskFilesUpload()
|
||||||
|
{
|
||||||
|
if (!$this->authorizeTask('save', $this->dataPermissions()) || !isset($_FILES)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var Config $config */
|
||||||
|
$config = $this->grav['config'];
|
||||||
|
$data = $this->view == 'pages' ? $this->admin->page(true) : $this->prepareData([]);
|
||||||
|
$settings = $data->blueprints()->schema()->getProperty($this->post['name']);
|
||||||
|
$settings = (object)array_merge(
|
||||||
|
['avoid_overwriting' => false,
|
||||||
|
'random_name' => false,
|
||||||
|
'accept' => ['image/*'],
|
||||||
|
'limit' => 10,
|
||||||
|
'filesize' => $config->get('system.media.upload_limit', 5242880) // 5MB
|
||||||
|
],
|
||||||
|
(array)$settings,
|
||||||
|
['name' => $this->post['name']]
|
||||||
|
);
|
||||||
|
|
||||||
|
$upload = $this->normalizeFiles($_FILES['data'], $settings->name);
|
||||||
|
|
||||||
|
if (!isset($settings->destination)) {
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => $this->admin->translate('PLUGIN_ADMIN.DESTINATION_NOT_SPECIFIED', null)
|
||||||
|
];
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not use self@ outside of pages
|
||||||
|
if ($this->view != 'pages' && in_array($settings->destination, ['@self', 'self@'])) {
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => sprintf($this->admin->translate('PLUGIN_ADMIN.FILEUPLOAD_PREVENT_SELF', null), $settings->destination)
|
||||||
|
];
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle errors and breaks without proceeding further
|
||||||
|
if ($upload->file->error != UPLOAD_ERR_OK) {
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => sprintf($this->admin->translate('PLUGIN_ADMIN.FILEUPLOAD_UNABLE_TO_UPLOAD', null), $upload->file->name,
|
||||||
|
$this->upload_errors[$upload->file->error])
|
||||||
|
];
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// Remove the error object to avoid storing it
|
||||||
|
unset($upload->file->error);
|
||||||
|
|
||||||
|
// we need to move the file at this stage or else
|
||||||
|
// it won't be available upon save later on
|
||||||
|
// since php removes it from the upload location
|
||||||
|
$tmp_dir = Admin::getTempDir();
|
||||||
|
$tmp_file = $upload->file->tmp_name;
|
||||||
|
$tmp = $tmp_dir . '/uploaded-files/' . basename($tmp_file);
|
||||||
|
|
||||||
|
Folder::create(dirname($tmp));
|
||||||
|
if (!move_uploaded_file($tmp_file, $tmp)) {
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => sprintf($this->admin->translate('PLUGIN_ADMIN.FILEUPLOAD_UNABLE_TO_MOVE', null), '', $tmp)
|
||||||
|
];
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$upload->file->tmp_name = $tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle file size limits
|
||||||
|
$settings->filesize *= 1048576; // 2^20 [MB in Bytes]
|
||||||
|
if ($settings->filesize > 0 && $upload->file->size > $settings->filesize) {
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => $this->admin->translate('PLUGIN_ADMIN.EXCEEDED_GRAV_FILESIZE_LIMIT')
|
||||||
|
];
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Handle Accepted file types
|
||||||
|
// Accept can only be mime types (image/png | image/*) or file extensions (.pdf|.jpg)
|
||||||
|
$accepted = false;
|
||||||
|
$errors = [];
|
||||||
|
foreach ((array)$settings->accept as $type) {
|
||||||
|
// Force acceptance of any file when star notation
|
||||||
|
if ($type == '*') {
|
||||||
|
$accepted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$isMime = strstr($type, '/');
|
||||||
|
$find = str_replace('*', '.*', $type);
|
||||||
|
|
||||||
|
$match = preg_match('#' . $find . '$#', $isMime ? $upload->file->type : $upload->file->name);
|
||||||
|
if (!$match) {
|
||||||
|
$message = $isMime ? 'The MIME type "' . $upload->file->type . '"' : 'The File Extension';
|
||||||
|
$errors[] = $message . ' for the file "' . $upload->file->name . '" is not an accepted.';
|
||||||
|
$accepted |= false;
|
||||||
|
} else {
|
||||||
|
$accepted |= true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$accepted) {
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => implode('<br />', $errors)
|
||||||
|
];
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the current session of the uploaded files for the field
|
||||||
|
// and initialize it if it doesn't exist
|
||||||
|
$sessionField = base64_encode($this->grav['uri']->url());
|
||||||
|
$flash = $this->admin->session()->getFlashObject('files-upload');
|
||||||
|
if (!$flash) {
|
||||||
|
$flash = [];
|
||||||
|
}
|
||||||
|
if (!isset($flash[$sessionField])) {
|
||||||
|
$flash[$sessionField] = [];
|
||||||
|
}
|
||||||
|
if (!isset($flash[$sessionField][$upload->field])) {
|
||||||
|
$flash[$sessionField][$upload->field] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set destination
|
||||||
|
$destination = Folder::getRelativePath(rtrim($settings->destination, '/'));
|
||||||
|
$destination = $this->admin->getPagePathFromToken($destination);
|
||||||
|
|
||||||
|
// Create destination if needed
|
||||||
|
if (!is_dir($destination)) {
|
||||||
|
Folder::mkdir($destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate random name if required
|
||||||
|
if ($settings->random_name) { // TODO: document
|
||||||
|
$extension = pathinfo($upload->file->name)['extension'];
|
||||||
|
$upload->file->name = Utils::generateRandomString(15) . '.' . $extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle conflicting name if needed
|
||||||
|
if ($settings->avoid_overwriting) { // TODO: document
|
||||||
|
if (file_exists($destination . '/' . $upload->file->name)) {
|
||||||
|
$upload->file->name = date('YmdHis') . '-' . $upload->file->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare object for later save
|
||||||
|
$path = $destination . '/' . $upload->file->name;
|
||||||
|
$upload->file->path = $path;
|
||||||
|
// $upload->file->route = $page ? $path : null;
|
||||||
|
|
||||||
|
// Prepare data to be saved later
|
||||||
|
$flash[$sessionField][$upload->field][$path] = (array)$upload->file;
|
||||||
|
|
||||||
|
// Finally store the new uploaded file in the field session
|
||||||
|
$this->admin->session()->setFlashObject('files-upload', $flash);
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'success',
|
||||||
|
'session' => \json_encode([
|
||||||
|
'sessionField' => base64_encode($this->grav['uri']->url()),
|
||||||
|
'path' => $upload->file->path,
|
||||||
|
'field' => $settings->name
|
||||||
|
])
|
||||||
|
];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the user is allowed to perform the given task with its associated permissions
|
||||||
|
*
|
||||||
|
* @param string $task The task to execute
|
||||||
|
* @param array $permissions The permissions given
|
||||||
|
*
|
||||||
|
* @return bool True if authorized. False if not.
|
||||||
|
*/
|
||||||
|
protected function authorizeTask($task = '', $permissions = [])
|
||||||
|
{
|
||||||
|
if (!$this->admin->authorize($permissions)) {
|
||||||
|
if ($this->grav['uri']->extension() === 'json') {
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'unauthorized',
|
||||||
|
'message' => $this->admin->translate('PLUGIN_ADMIN.INSUFFICIENT_PERMISSIONS_FOR_TASK') . ' ' . $task . '.'
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$this->admin->setMessage($this->admin->translate('PLUGIN_ADMIN.INSUFFICIENT_PERMISSIONS_FOR_TASK') . ' ' . $task . '.',
|
||||||
|
'error');
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the permissions needed to access a given view
|
||||||
|
*
|
||||||
|
* @return array An array of permissions
|
||||||
|
*/
|
||||||
|
protected function dataPermissions()
|
||||||
|
{
|
||||||
|
$type = $this->view;
|
||||||
|
$permissions = ['admin.super'];
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case 'configuration':
|
||||||
|
case 'system':
|
||||||
|
$permissions[] = 'admin.configuration';
|
||||||
|
break;
|
||||||
|
case 'settings':
|
||||||
|
case 'site':
|
||||||
|
$permissions[] = 'admin.settings';
|
||||||
|
break;
|
||||||
|
case 'plugins':
|
||||||
|
$permissions[] = 'admin.plugins';
|
||||||
|
break;
|
||||||
|
case 'themes':
|
||||||
|
$permissions[] = 'admin.themes';
|
||||||
|
break;
|
||||||
|
case 'users':
|
||||||
|
$permissions[] = 'admin.users';
|
||||||
|
break;
|
||||||
|
case 'pages':
|
||||||
|
$permissions[] = 'admin.pages';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the configuration data for a given view & post
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function prepareData(array $data)
|
||||||
|
{
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method to normalize the $_FILES array
|
||||||
|
*
|
||||||
|
* @param array $data $_FILES starting point data
|
||||||
|
* @param string $key
|
||||||
|
*
|
||||||
|
* @return object a new Object with a normalized list of files
|
||||||
|
*/
|
||||||
|
protected function normalizeFiles($data, $key = '')
|
||||||
|
{
|
||||||
|
$files = new \stdClass();
|
||||||
|
$files->field = $key;
|
||||||
|
$files->file = new \stdClass();
|
||||||
|
|
||||||
|
foreach ($data as $fieldName => $fieldValue) {
|
||||||
|
// Since Files Upload are always happening via Ajax
|
||||||
|
// we are not interested in handling `multiple="true"`
|
||||||
|
// because they are always handled one at a time.
|
||||||
|
// For this reason we normalize the value to string,
|
||||||
|
// in case it is arriving as an array.
|
||||||
|
$value = (array)Utils::getDotNotation($fieldValue, $key);
|
||||||
|
$files->file->{$fieldName} = array_shift($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a file from the flash object session, before it gets saved
|
||||||
|
*
|
||||||
|
* @return bool True if the action was performed.
|
||||||
|
*/
|
||||||
|
public function taskFilesSessionRemove()
|
||||||
|
{
|
||||||
|
if (!$this->authorizeTask('save', $this->dataPermissions()) || !isset($_FILES)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the current session of the uploaded files for the field
|
||||||
|
// and initialize it if it doesn't exist
|
||||||
|
$sessionField = base64_encode($this->grav['uri']->url());
|
||||||
|
$request = \json_decode($this->post['session']);
|
||||||
|
|
||||||
|
// Ensure the URI requested matches the current one, otherwise fail
|
||||||
|
if ($request->sessionField !== $sessionField) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the flash object and remove the requested file from it
|
||||||
|
$flash = $this->admin->session()->getFlashObject('files-upload');
|
||||||
|
$endpoint = $flash[$request->sessionField][$request->field][$request->path];
|
||||||
|
|
||||||
|
if (isset($endpoint)) {
|
||||||
|
if (file_exists($endpoint['tmp_name'])) {
|
||||||
|
unlink($endpoint['tmp_name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk backward to cleanup any empty field that's left
|
||||||
|
// Field
|
||||||
|
if (!count($flash[$request->sessionField][$request->field])) {
|
||||||
|
unset($flash[$request->sessionField][$request->field]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Session Field
|
||||||
|
if (!count($flash[$request->sessionField])) {
|
||||||
|
unset($flash[$request->sessionField]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If there's anything left to restore in the flash object, do so
|
||||||
|
if (count($flash)) {
|
||||||
|
$this->admin->session()->setFlashObject('files-upload', $flash);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->admin->json_response = ['status' => 'success'];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect to the route stored in $this->redirect
|
||||||
|
*/
|
||||||
|
public function redirect()
|
||||||
|
{
|
||||||
|
if (!$this->redirect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$base = $this->admin->base;
|
||||||
|
$this->redirect = '/' . ltrim($this->redirect, '/');
|
||||||
|
$multilang = $this->isMultilang();
|
||||||
|
|
||||||
|
$redirect = '';
|
||||||
|
if ($multilang) {
|
||||||
|
// if base path does not already contain the lang code, add it
|
||||||
|
$langPrefix = '/' . $this->grav['session']->admin_lang;
|
||||||
|
if (!Utils::startsWith($base, $langPrefix . '/')) {
|
||||||
|
$base = $langPrefix . $base;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now the first 4 chars of base contain the lang code.
|
||||||
|
// if redirect path already contains the lang code, and is != than the base lang code, then use redirect path as-is
|
||||||
|
if (Utils::pathPrefixedByLangCode($base) && Utils::pathPrefixedByLangCode($this->redirect)
|
||||||
|
&& substr($base,
|
||||||
|
0, 4) != substr($this->redirect, 0, 4)
|
||||||
|
) {
|
||||||
|
$redirect = $this->redirect;
|
||||||
|
} else {
|
||||||
|
if (!Utils::startsWith($this->redirect, $base)) {
|
||||||
|
$this->redirect = $base . $this->redirect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (!Utils::startsWith($this->redirect, $base)) {
|
||||||
|
$this->redirect = $base . $this->redirect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$redirect) {
|
||||||
|
$redirect = $this->redirect;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->grav->redirect($redirect, $this->redirectCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare and return POST data.
|
||||||
|
*
|
||||||
|
* @param array $post
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getPost($post)
|
||||||
|
{
|
||||||
|
unset($post['task']);
|
||||||
|
|
||||||
|
// Decode JSON encoded fields and merge them to data.
|
||||||
|
if (isset($post['_json'])) {
|
||||||
|
$post = array_replace_recursive($post, $this->jsonDecode($post['_json']));
|
||||||
|
unset($post['_json']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$post = $this->cleanDataKeys($post);
|
||||||
|
|
||||||
|
return $post;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively JSON decode data.
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function jsonDecode(array $data)
|
||||||
|
{
|
||||||
|
foreach ($data as &$value) {
|
||||||
|
if (is_array($value)) {
|
||||||
|
$value = $this->jsonDecode($value);
|
||||||
|
} else {
|
||||||
|
$value = json_decode($value, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function cleanDataKeys($source = [])
|
||||||
|
{
|
||||||
|
$out = [];
|
||||||
|
|
||||||
|
if (is_array($source)) {
|
||||||
|
foreach ($source as $key => $value) {
|
||||||
|
$key = str_replace('%5B', '[', str_replace('%5D', ']', $key));
|
||||||
|
if (is_array($value)) {
|
||||||
|
$out[$key] = $this->cleanDataKeys($value);
|
||||||
|
} else {
|
||||||
|
$out[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if multilang is active
|
||||||
|
*
|
||||||
|
* @return bool True if multilang is active
|
||||||
|
*/
|
||||||
|
protected function isMultilang()
|
||||||
|
{
|
||||||
|
return count($this->grav['config']->get('system.languages.supported', [])) > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Grav\Common\Page\Page|\Grav\Common\Data\Data $obj
|
||||||
|
*
|
||||||
|
* @return \Grav\Common\Page\Page|\Grav\Common\Data\Data
|
||||||
|
*/
|
||||||
|
protected function storeFiles($obj)
|
||||||
|
{
|
||||||
|
// Process previously uploaded files for the current URI
|
||||||
|
// and finally store them. Everything else will get discarded
|
||||||
|
$queue = $this->admin->session()->getFlashObject('files-upload');
|
||||||
|
$queue = $queue[base64_encode($this->grav['uri']->url())];
|
||||||
|
if (is_array($queue)) {
|
||||||
|
foreach ($queue as $key => $files) {
|
||||||
|
foreach ($files as $destination => $file) {
|
||||||
|
if (!rename($file['tmp_name'], $destination)) {
|
||||||
|
throw new \RuntimeException(sprintf($this->admin->translate('PLUGIN_ADMIN.FILEUPLOAD_UNABLE_TO_MOVE', null),
|
||||||
|
'"' . $file['tmp_name'] . '"', $destination));
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($files[$destination]['tmp_name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->view == 'pages') {
|
||||||
|
$keys = explode('.', preg_replace('/^header./', '', $key));
|
||||||
|
$init_key = array_shift($keys);
|
||||||
|
if (count($keys) > 0) {
|
||||||
|
$new_data = isset($obj->header()->$init_key) ? $obj->header()->$init_key : [];
|
||||||
|
Utils::setDotNotation($new_data, implode('.', $keys), $files, true);
|
||||||
|
} else {
|
||||||
|
$new_data = $files;
|
||||||
|
}
|
||||||
|
if (isset($data['header'][$init_key])) {
|
||||||
|
$obj->modifyHeader($init_key, array_replace_recursive([], $data['header'][$init_key], $new_data));
|
||||||
|
} else {
|
||||||
|
$obj->modifyHeader($init_key, $new_data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: [this is JS handled] if it's single file, remove existing and use set, if it's multiple, use join
|
||||||
|
$obj->join($key, $files); // stores
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by the filepicker field to get a list of files in a folder.
|
||||||
|
*/
|
||||||
|
protected function taskGetFilesInFolder()
|
||||||
|
{
|
||||||
|
if (!$this->authorizeTask('save', $this->dataPermissions())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->view == 'pages' ? $this->admin->page(true) : $this->prepareData([]);
|
||||||
|
$settings = $data->blueprints()->schema()->getProperty($this->post['name']);
|
||||||
|
|
||||||
|
if (isset($settings['folder'])) {
|
||||||
|
$folder = $settings['folder'];
|
||||||
|
} else {
|
||||||
|
$folder = '@self';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not use self@ outside of pages
|
||||||
|
if ($this->view != 'pages' && in_array($folder, ['@self', 'self@'])) {
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => sprintf($this->admin->translate('PLUGIN_ADMIN.FILEUPLOAD_PREVENT_SELF', null), $folder)
|
||||||
|
];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set destination
|
||||||
|
$folder = Folder::getRelativePath(rtrim($folder, '/'));
|
||||||
|
$folder = $this->admin->getPagePathFromToken($folder);
|
||||||
|
|
||||||
|
$media = new Media($folder);
|
||||||
|
$available_files = [];
|
||||||
|
|
||||||
|
foreach ($media->all() as $name => $medium) {
|
||||||
|
$available_files[] = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peak in the flashObject for optimistic filepicker updates
|
||||||
|
$pending_files = [];
|
||||||
|
$sessionField = base64_encode($this->grav['uri']->url());
|
||||||
|
$flash = $this->admin->session()->getFlashObject('files-upload');
|
||||||
|
|
||||||
|
if ($flash && isset($flash[$sessionField])) {
|
||||||
|
foreach ($flash[$sessionField] as $field => $data) {
|
||||||
|
foreach ($data as $file) {
|
||||||
|
if (dirname($file['path']) === $folder) {
|
||||||
|
$pending_files[] = $file['name'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->admin->session()->setFlashObject('files-upload', $flash);
|
||||||
|
|
||||||
|
// Handle Accepted file types
|
||||||
|
// Accept can only be file extensions (.pdf|.jpg)
|
||||||
|
if (isset($settings['accept'])) {
|
||||||
|
$available_files = array_filter($available_files, function ($file) use ($settings) {
|
||||||
|
return $this->filterAcceptedFiles($file, $settings);
|
||||||
|
});
|
||||||
|
|
||||||
|
$pending_files = array_filter($pending_files, function ($file) use ($settings) {
|
||||||
|
return $this->filterAcceptedFiles($file, $settings);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'success',
|
||||||
|
'files' => array_values($available_files),
|
||||||
|
'pending' => array_values($pending_files),
|
||||||
|
'folder' => $folder
|
||||||
|
];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function filterAcceptedFiles($file, $settings)
|
||||||
|
{
|
||||||
|
$valid = false;
|
||||||
|
|
||||||
|
foreach ((array)$settings['accept'] as $type) {
|
||||||
|
$find = str_replace('*', '.*', $type);
|
||||||
|
$valid |= preg_match('#' . $find . '$#', $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle deleting a file from a blueprint
|
||||||
|
*
|
||||||
|
* @return bool True if the action was performed.
|
||||||
|
*/
|
||||||
|
protected function taskRemoveFileFromBlueprint()
|
||||||
|
{
|
||||||
|
$uri = $this->grav['uri'];
|
||||||
|
$blueprint = base64_decode($uri->param('blueprint'));
|
||||||
|
$path = base64_decode($uri->param('path'));
|
||||||
|
$proute = base64_decode($uri->param('proute'));
|
||||||
|
$type = $uri->param('type');
|
||||||
|
$field = $uri->param('field');
|
||||||
|
|
||||||
|
$event = $this->grav->fireEvent('onAdminCanSave', new Event(['controller' => &$this]));
|
||||||
|
if (!$event['can_save']) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->taskRemoveMedia();
|
||||||
|
|
||||||
|
if ($type == 'pages') {
|
||||||
|
$page = $this->admin->page(true, $proute);
|
||||||
|
$keys = explode('.', preg_replace('/^header./', '', $field));
|
||||||
|
$header = (array)$page->header();
|
||||||
|
$data_path = implode('.', $keys);
|
||||||
|
$data = Utils::getDotNotation($header, $data_path);
|
||||||
|
|
||||||
|
if (isset($data[$path])) {
|
||||||
|
unset($data[$path]);
|
||||||
|
Utils::setDotNotation($header, $data_path, $data);
|
||||||
|
$page->header($header);
|
||||||
|
}
|
||||||
|
|
||||||
|
$page->save();
|
||||||
|
} else {
|
||||||
|
$blueprint_prefix = $type == 'config' ? '' : $type . '.';
|
||||||
|
$blueprint_name = str_replace('/blueprints', '', str_replace('config/', '', $blueprint));
|
||||||
|
$blueprint_field = $blueprint_prefix . $blueprint_name . '.' . $field;
|
||||||
|
$files = $this->grav['config']->get($blueprint_field);
|
||||||
|
|
||||||
|
if ($files) {
|
||||||
|
foreach ($files as $key => $value) {
|
||||||
|
if ($key == $path) {
|
||||||
|
unset($files[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->grav['config']->set($blueprint_field, $files);
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case 'config':
|
||||||
|
$data = $this->grav['config']->get($blueprint_name);
|
||||||
|
$config = $this->admin->data($blueprint, $data);
|
||||||
|
$config->save();
|
||||||
|
break;
|
||||||
|
case 'themes':
|
||||||
|
Theme::saveConfig($blueprint_name);
|
||||||
|
break;
|
||||||
|
case 'plugins':
|
||||||
|
Plugin::saveConfig($blueprint_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'success',
|
||||||
|
'message' => $this->admin->translate('PLUGIN_ADMIN.REMOVE_SUCCESSFUL')
|
||||||
|
];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles removing a media file
|
||||||
|
*
|
||||||
|
* @return bool True if the action was performed
|
||||||
|
*/
|
||||||
|
public function taskRemoveMedia()
|
||||||
|
{
|
||||||
|
if (!$this->canEditMedia()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$filename = base64_decode($this->grav['uri']->param('route'));
|
||||||
|
|
||||||
|
$file = File::instance($filename);
|
||||||
|
$resultRemoveMedia = false;
|
||||||
|
$resultRemoveMediaMeta = true;
|
||||||
|
|
||||||
|
if ($file->exists()) {
|
||||||
|
$resultRemoveMedia = $file->delete();
|
||||||
|
|
||||||
|
$metaFilePath = $filename . '.meta.yaml';
|
||||||
|
$metaFilePath = str_replace('@3x', '', $metaFilePath);
|
||||||
|
$metaFilePath = str_replace('@2x', '', $metaFilePath);
|
||||||
|
|
||||||
|
if (is_file($metaFilePath)) {
|
||||||
|
$metaFile = File::instance($metaFilePath);
|
||||||
|
$resultRemoveMediaMeta = $metaFile->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($resultRemoveMedia && $resultRemoveMediaMeta) {
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'success',
|
||||||
|
'message' => $this->admin->translate('PLUGIN_ADMIN.REMOVE_SUCCESSFUL')
|
||||||
|
];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
$this->admin->json_response = [
|
||||||
|
'status' => 'success',
|
||||||
|
'message' => $this->admin->translate('PLUGIN_ADMIN.REMOVE_FAILED')
|
||||||
|
];
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the user can edit media
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
*
|
||||||
|
* @return bool True if the media action is allowed
|
||||||
|
*/
|
||||||
|
protected function canEditMedia($type = 'media')
|
||||||
|
{
|
||||||
|
if (!$this->authorizeTask('edit media', ['admin.' . $type, 'admin.super'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Grav\Plugin;
|
namespace Grav\Plugin\Admin;
|
||||||
|
|
||||||
use Grav\Common\Config\Config;
|
use Grav\Common\Config\Config;
|
||||||
use Grav\Common\Grav;
|
use Grav\Common\Grav;
|
||||||
use Grav\Common\Page\Page;
|
use Grav\Common\Page\Page;
|
||||||
use Grav\Common\Data;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Popularity
|
* Class Popularity
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Grav\Plugin;
|
namespace Grav\Plugin\Admin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Admin theme object
|
* Admin theme object
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ class Utils
|
|||||||
/**
|
/**
|
||||||
* Matches an email to a user
|
* Matches an email to a user
|
||||||
*
|
*
|
||||||
|
* @param $email
|
||||||
|
*
|
||||||
* @return User
|
* @return User
|
||||||
*/
|
*/
|
||||||
public static function findUserByEmail($email)
|
public static function findUserByEmail($email)
|
||||||
|
|||||||
111
composer.lock
generated
111
composer.lock
generated
@@ -166,16 +166,16 @@
|
|||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
{
|
{
|
||||||
"name": "behat/gherkin",
|
"name": "behat/gherkin",
|
||||||
"version": "v4.4.4",
|
"version": "v4.4.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/Behat/Gherkin.git",
|
"url": "https://github.com/Behat/Gherkin.git",
|
||||||
"reference": "cf8cc94647101e02a33d690245896d83d880aea1"
|
"reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/Behat/Gherkin/zipball/cf8cc94647101e02a33d690245896d83d880aea1",
|
"url": "https://api.github.com/repos/Behat/Gherkin/zipball/5c14cff4f955b17d20d088dec1bde61c0539ec74",
|
||||||
"reference": "cf8cc94647101e02a33d690245896d83d880aea1",
|
"reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -221,20 +221,20 @@
|
|||||||
"gherkin",
|
"gherkin",
|
||||||
"parser"
|
"parser"
|
||||||
],
|
],
|
||||||
"time": "2016-09-18 12:16:14"
|
"time": "2016-10-30 11:50:56"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "codeception/codeception",
|
"name": "codeception/codeception",
|
||||||
"version": "2.2.5",
|
"version": "2.2.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/Codeception/Codeception.git",
|
"url": "https://github.com/Codeception/Codeception.git",
|
||||||
"reference": "b4729341e469d0f174f3cade85718ff5bf8dd751"
|
"reference": "5fbe312c8138e71458ec1e715b0ce262331ca5a2"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/b4729341e469d0f174f3cade85718ff5bf8dd751",
|
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/5fbe312c8138e71458ec1e715b0ce262331ca5a2",
|
||||||
"reference": "b4729341e469d0f174f3cade85718ff5bf8dd751",
|
"reference": "5fbe312c8138e71458ec1e715b0ce262331ca5a2",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -312,7 +312,7 @@
|
|||||||
"functional testing",
|
"functional testing",
|
||||||
"unit testing"
|
"unit testing"
|
||||||
],
|
],
|
||||||
"time": "2016-09-29 01:29:59"
|
"time": "2016-10-27 00:00:34"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "doctrine/instantiator",
|
"name": "doctrine/instantiator",
|
||||||
@@ -370,24 +370,25 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "facebook/webdriver",
|
"name": "facebook/webdriver",
|
||||||
"version": "1.1.3",
|
"version": "1.2.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/facebook/php-webdriver.git",
|
"url": "https://github.com/facebook/php-webdriver.git",
|
||||||
"reference": "b7186fb1bcfda956d237f59face250d06ef47253"
|
"reference": "af21de3ae5306a8ca0bcc02a19735dadc43e83f3"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/facebook/php-webdriver/zipball/b7186fb1bcfda956d237f59face250d06ef47253",
|
"url": "https://api.github.com/repos/facebook/php-webdriver/zipball/af21de3ae5306a8ca0bcc02a19735dadc43e83f3",
|
||||||
"reference": "b7186fb1bcfda956d237f59face250d06ef47253",
|
"reference": "af21de3ae5306a8ca0bcc02a19735dadc43e83f3",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
"php": ">=5.3.19"
|
"php": "^5.5 || ~7.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"friendsofphp/php-cs-fixer": "^1.11",
|
"friendsofphp/php-cs-fixer": "^1.11",
|
||||||
|
"php-mock/php-mock-phpunit": "^1.1",
|
||||||
"phpunit/phpunit": "4.6.* || ~5.0",
|
"phpunit/phpunit": "4.6.* || ~5.0",
|
||||||
"squizlabs/php_codesniffer": "^2.6"
|
"squizlabs/php_codesniffer": "^2.6"
|
||||||
},
|
},
|
||||||
@@ -412,7 +413,7 @@
|
|||||||
"selenium",
|
"selenium",
|
||||||
"webdriver"
|
"webdriver"
|
||||||
],
|
],
|
||||||
"time": "2016-08-10 00:44:08"
|
"time": "2016-10-14 15:16:51"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "fzaninotto/faker",
|
"name": "fzaninotto/faker",
|
||||||
@@ -635,16 +636,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "myclabs/deep-copy",
|
"name": "myclabs/deep-copy",
|
||||||
"version": "1.5.4",
|
"version": "1.5.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||||
"reference": "ea74994a3dc7f8d2f65a06009348f2d63c81e61f"
|
"reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/ea74994a3dc7f8d2f65a06009348f2d63c81e61f",
|
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/399c1f9781e222f6eb6cc238796f5200d1b7f108",
|
||||||
"reference": "ea74994a3dc7f8d2f65a06009348f2d63c81e61f",
|
"reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -673,7 +674,7 @@
|
|||||||
"object",
|
"object",
|
||||||
"object graph"
|
"object graph"
|
||||||
],
|
],
|
||||||
"time": "2016-09-16 13:37:59"
|
"time": "2016-10-31 17:19:45"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpdocumentor/reflection-common",
|
"name": "phpdocumentor/reflection-common",
|
||||||
@@ -885,16 +886,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-code-coverage",
|
"name": "phpunit/php-code-coverage",
|
||||||
"version": "4.0.1",
|
"version": "4.0.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||||
"reference": "5f3f7e736d6319d5f1fc402aff8b026da26709a3"
|
"reference": "6cba06ff75a1a63a71033e1a01b89056f3af1e8d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5f3f7e736d6319d5f1fc402aff8b026da26709a3",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6cba06ff75a1a63a71033e1a01b89056f3af1e8d",
|
||||||
"reference": "5f3f7e736d6319d5f1fc402aff8b026da26709a3",
|
"reference": "6cba06ff75a1a63a71033e1a01b89056f3af1e8d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -944,7 +945,7 @@
|
|||||||
"testing",
|
"testing",
|
||||||
"xunit"
|
"xunit"
|
||||||
],
|
],
|
||||||
"time": "2016-07-26 14:39:29"
|
"time": "2016-11-01 05:06:24"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-file-iterator",
|
"name": "phpunit/php-file-iterator",
|
||||||
@@ -1129,16 +1130,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit",
|
"name": "phpunit/phpunit",
|
||||||
"version": "5.6.1",
|
"version": "5.6.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||||
"reference": "60c32c5b5e79c2248001efa2560f831da11cc2d7"
|
"reference": "cd13b23ac5a519a4708e00736c26ee0bb28b2e01"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/60c32c5b5e79c2248001efa2560f831da11cc2d7",
|
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/cd13b23ac5a519a4708e00736c26ee0bb28b2e01",
|
||||||
"reference": "60c32c5b5e79c2248001efa2560f831da11cc2d7",
|
"reference": "cd13b23ac5a519a4708e00736c26ee0bb28b2e01",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -1207,7 +1208,7 @@
|
|||||||
"testing",
|
"testing",
|
||||||
"xunit"
|
"xunit"
|
||||||
],
|
],
|
||||||
"time": "2016-10-07 13:03:26"
|
"time": "2016-10-25 07:40:25"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit-mock-objects",
|
"name": "phpunit/phpunit-mock-objects",
|
||||||
@@ -1880,7 +1881,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/browser-kit",
|
"name": "symfony/browser-kit",
|
||||||
"version": "v3.1.5",
|
"version": "v3.1.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/browser-kit.git",
|
"url": "https://github.com/symfony/browser-kit.git",
|
||||||
@@ -1937,16 +1938,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/console",
|
"name": "symfony/console",
|
||||||
"version": "v3.1.5",
|
"version": "v3.1.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/console.git",
|
"url": "https://github.com/symfony/console.git",
|
||||||
"reference": "6cb0872fb57b38b3b09ff213c21ed693956b9eb0"
|
"reference": "c99da1119ae61e15de0e4829196b9fba6f73d065"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/console/zipball/6cb0872fb57b38b3b09ff213c21ed693956b9eb0",
|
"url": "https://api.github.com/repos/symfony/console/zipball/c99da1119ae61e15de0e4829196b9fba6f73d065",
|
||||||
"reference": "6cb0872fb57b38b3b09ff213c21ed693956b9eb0",
|
"reference": "c99da1119ae61e15de0e4829196b9fba6f73d065",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -1994,11 +1995,11 @@
|
|||||||
],
|
],
|
||||||
"description": "Symfony Console Component",
|
"description": "Symfony Console Component",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2016-09-28 00:11:12"
|
"time": "2016-10-06 01:44:51"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/css-selector",
|
"name": "symfony/css-selector",
|
||||||
"version": "v3.1.5",
|
"version": "v3.1.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/css-selector.git",
|
"url": "https://github.com/symfony/css-selector.git",
|
||||||
@@ -2051,7 +2052,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/debug",
|
"name": "symfony/debug",
|
||||||
"version": "v3.1.5",
|
"version": "v3.1.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/debug.git",
|
"url": "https://github.com/symfony/debug.git",
|
||||||
@@ -2108,16 +2109,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/dom-crawler",
|
"name": "symfony/dom-crawler",
|
||||||
"version": "v3.1.5",
|
"version": "v3.1.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/dom-crawler.git",
|
"url": "https://github.com/symfony/dom-crawler.git",
|
||||||
"reference": "bb7395e8b1db3654de82b9f35d019958276de4d7"
|
"reference": "59eee3c76eb89f21857798620ebdad7a05ad14f4"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/bb7395e8b1db3654de82b9f35d019958276de4d7",
|
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/59eee3c76eb89f21857798620ebdad7a05ad14f4",
|
||||||
"reference": "bb7395e8b1db3654de82b9f35d019958276de4d7",
|
"reference": "59eee3c76eb89f21857798620ebdad7a05ad14f4",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -2160,20 +2161,20 @@
|
|||||||
],
|
],
|
||||||
"description": "Symfony DomCrawler Component",
|
"description": "Symfony DomCrawler Component",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2016-08-05 08:37:39"
|
"time": "2016-10-18 15:46:07"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/event-dispatcher",
|
"name": "symfony/event-dispatcher",
|
||||||
"version": "v3.1.5",
|
"version": "v3.1.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||||
"reference": "c0c00c80b3a69132c4e55c3e7db32b4a387615e5"
|
"reference": "28b0832b2553ffb80cabef6a7a812ff1e670c0bc"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c0c00c80b3a69132c4e55c3e7db32b4a387615e5",
|
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/28b0832b2553ffb80cabef6a7a812ff1e670c0bc",
|
||||||
"reference": "c0c00c80b3a69132c4e55c3e7db32b4a387615e5",
|
"reference": "28b0832b2553ffb80cabef6a7a812ff1e670c0bc",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -2220,11 +2221,11 @@
|
|||||||
],
|
],
|
||||||
"description": "Symfony EventDispatcher Component",
|
"description": "Symfony EventDispatcher Component",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2016-07-19 10:45:57"
|
"time": "2016-10-13 06:28:43"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/finder",
|
"name": "symfony/finder",
|
||||||
"version": "v3.1.5",
|
"version": "v3.1.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/finder.git",
|
"url": "https://github.com/symfony/finder.git",
|
||||||
@@ -2332,16 +2333,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/yaml",
|
"name": "symfony/yaml",
|
||||||
"version": "v3.1.5",
|
"version": "v3.1.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/yaml.git",
|
"url": "https://github.com/symfony/yaml.git",
|
||||||
"reference": "368b9738d4033c8b93454cb0dbd45d305135a6d3"
|
"reference": "7ff51b06c6c3d5cc6686df69004a42c69df09e27"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/368b9738d4033c8b93454cb0dbd45d305135a6d3",
|
"url": "https://api.github.com/repos/symfony/yaml/zipball/7ff51b06c6c3d5cc6686df69004a42c69df09e27",
|
||||||
"reference": "368b9738d4033c8b93454cb0dbd45d305135a6d3",
|
"reference": "7ff51b06c6c3d5cc6686df69004a42c69df09e27",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -2377,7 +2378,7 @@
|
|||||||
],
|
],
|
||||||
"description": "Symfony Yaml Component",
|
"description": "Symfony Yaml Component",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2016-09-25 08:27:07"
|
"time": "2016-10-24 18:41:13"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "webmozart/assert",
|
"name": "webmozart/assert",
|
||||||
|
|||||||
@@ -108,7 +108,10 @@ export default class FilesField {
|
|||||||
|
|
||||||
dropzone.files.push(mock);
|
dropzone.files.push(mock);
|
||||||
dropzone.options.addedfile.call(dropzone, mock);
|
dropzone.options.addedfile.call(dropzone, mock);
|
||||||
if (mock.type.match(/^image\//)) dropzone.options.thumbnail.call(dropzone, mock, data.path);
|
if (mock.type.match(/^image\//)) {
|
||||||
|
dropzone.options.thumbnail.call(dropzone, mock, data.path);
|
||||||
|
dropzone.createThumbnailFromUrl(mock, data.path);
|
||||||
|
}
|
||||||
|
|
||||||
file.remove();
|
file.remove();
|
||||||
});
|
});
|
||||||
|
|||||||
2
themes/grav/js/admin.min.js
vendored
2
themes/grav/js/admin.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -30,7 +30,7 @@
|
|||||||
{% set files = global.files %}
|
{% set files = global.files %}
|
||||||
{% set config = global.grav.config %}
|
{% set config = global.grav.config %}
|
||||||
{% set route = global.context.route() %}
|
{% set route = global.context.route() %}
|
||||||
{% set type = get_class(global.context) == 'Grav\\Common\\Page\\Page' ? 'pages' : global.plugin ? 'plugins' : global.theme ? 'themes' : 'config' %}
|
{% set type = global.blueprint_type ? global.blueprint_type : (get_class(global.context) == 'Grav\\Common\\Page\\Page' ? 'pages' : global.plugin ? 'plugins' : global.theme ? 'themes' : 'config') %}
|
||||||
|
|
||||||
{% set blueprint_name = global.blueprints.getFilename %}
|
{% set blueprint_name = global.blueprints.getFilename %}
|
||||||
{% if type == 'pages' %}
|
{% if type == 'pages' %}
|
||||||
@@ -38,8 +38,9 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% set blueprint = base64_encode(blueprint_name) %}
|
{% set blueprint = base64_encode(blueprint_name) %}
|
||||||
{% set real_path = global.admin.getPagePathFromToken(path) %}
|
{% set real_path = global.admin.getPagePathFromToken(path) %}
|
||||||
{% set remove = uri.addNonce(global.base_url_relative ~
|
{% set remove = global.file_url_remove ? global.file_url_remove : (global.base_url_relative ~ '/media.json') %}
|
||||||
'/media.json' ~
|
{% set remove = uri.addNonce(
|
||||||
|
remove ~
|
||||||
'/route' ~ config.system.param_sep ~ base64_encode(global.base_path ~ '/' ~ real_path) ~
|
'/route' ~ config.system.param_sep ~ base64_encode(global.base_path ~ '/' ~ real_path) ~
|
||||||
'/task' ~ config.system.param_sep ~ 'removeFileFromBlueprint' ~
|
'/task' ~ config.system.param_sep ~ 'removeFileFromBlueprint' ~
|
||||||
'/proute' ~ config.system.param_sep ~ base64_encode(route) ~
|
'/proute' ~ config.system.param_sep ~ base64_encode(route) ~
|
||||||
@@ -59,7 +60,7 @@
|
|||||||
|
|
||||||
{% set settings = {name: field.name, paramName: (scope ~ field.name)|fieldName ~ (files.multiple ? '[]' : ''), limit: limit, filesize: files.filesize, accept: files.accept} %}
|
{% set settings = {name: field.name, paramName: (scope ~ field.name)|fieldName ~ (files.multiple ? '[]' : ''), limit: limit, filesize: files.filesize, accept: files.accept} %}
|
||||||
|
|
||||||
<div class="form-input-wrapper dropzone files-upload {% if field.fancy is not same as(false) %}form-input-file{% endif %} {{ field.size|default('xlarge') }}" data-grav-file-settings="{{ settings|json_encode|e('html_attr') }}">
|
<div class="form-input-wrapper dropzone files-upload {% if field.fancy is not same as(false) %}form-input-file{% endif %} {{ field.size|default('xlarge') }}" data-grav-file-settings="{{ settings|json_encode|e('html_attr') }}" {% if file_url_add %}data-file-url-add="{{ file_url_add }}"{% endif %} {% if file_url_add %}data-file-url-remove="{{ file_url_add }}"{% endif %}>
|
||||||
<input
|
<input
|
||||||
{# required attribute structures #}
|
{# required attribute structures #}
|
||||||
{% block input_attributes %}
|
{% block input_attributes %}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Grav\Plugin;
|
namespace Grav\Plugin\Admin;
|
||||||
|
|
||||||
use Grav\Common\Grav;
|
use Grav\Common\Grav;
|
||||||
use Grav\Common\Language\Language;
|
use Grav\Common\Language\Language;
|
||||||
|
|||||||
12
vendor/composer/ClassLoader.php
vendored
12
vendor/composer/ClassLoader.php
vendored
@@ -53,8 +53,8 @@ class ClassLoader
|
|||||||
|
|
||||||
private $useIncludePath = false;
|
private $useIncludePath = false;
|
||||||
private $classMap = array();
|
private $classMap = array();
|
||||||
|
|
||||||
private $classMapAuthoritative = false;
|
private $classMapAuthoritative = false;
|
||||||
|
private $missingClasses = array();
|
||||||
|
|
||||||
public function getPrefixes()
|
public function getPrefixes()
|
||||||
{
|
{
|
||||||
@@ -322,20 +322,20 @@ class ClassLoader
|
|||||||
if (isset($this->classMap[$class])) {
|
if (isset($this->classMap[$class])) {
|
||||||
return $this->classMap[$class];
|
return $this->classMap[$class];
|
||||||
}
|
}
|
||||||
if ($this->classMapAuthoritative) {
|
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$file = $this->findFileWithExtension($class, '.php');
|
$file = $this->findFileWithExtension($class, '.php');
|
||||||
|
|
||||||
// Search for Hack files if we are running on HHVM
|
// Search for Hack files if we are running on HHVM
|
||||||
if ($file === null && defined('HHVM_VERSION')) {
|
if (false === $file && defined('HHVM_VERSION')) {
|
||||||
$file = $this->findFileWithExtension($class, '.hh');
|
$file = $this->findFileWithExtension($class, '.hh');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($file === null) {
|
if (false === $file) {
|
||||||
// Remember that this class does not exist.
|
// Remember that this class does not exist.
|
||||||
return $this->classMap[$class] = false;
|
$this->missingClasses[$class] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $file;
|
return $file;
|
||||||
@@ -399,6 +399,8 @@ class ClassLoader
|
|||||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||||
return $file;
|
return $file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user