Merge branch 'release/1.8.2'

This commit is contained in:
Andy Miller
2018-05-24 12:11:47 -06:00
19 changed files with 101 additions and 50 deletions

View File

@@ -1,3 +1,19 @@
# v1.8.2
## 05/24/2018
1. [](#new)
* Added custom object support for filepicker field
* Don't allow saving of a user with no local account file
* Controls for `list` field were not in sync between top and bottom
1. [](#improved)
* More subtle `fieldset` styling
1. [](#bugfix)
* Check if `$object->blueprints()` exists in `onAdminAfterSave`
* When creating first user, check `admin.login` not `site.login`
* Fix admin login redirects for multisite setups
* Fixed issue with filepicker field where images wouldn't properly merge with the current value if in a page header
* Fixed media delete for streams
# v1.8.1 # v1.8.1
## 05/15/2018 ## 05/15/2018

View File

@@ -249,7 +249,7 @@ class AdminPlugin extends Plugin
unset($this->grav['user']); unset($this->grav['user']);
$this->grav['user'] = $user; $this->grav['user'] = $user;
$user->authenticated = true; $user->authenticated = true;
$user->authorized = $user->authorize('site.login'); $user->authorized = $user->authorize('admin.login');
$messages = $this->grav['messages']; $messages = $this->grav['messages'];
$messages->add($this->grav['language']->translate('PLUGIN_ADMIN.LOGIN_LOGGED_IN'), 'info'); $messages->add($this->grav['language']->translate('PLUGIN_ADMIN.LOGIN_LOGGED_IN'), 'info');
@@ -456,7 +456,9 @@ class AdminPlugin extends Plugin
$twig->twig_vars['location'] = $this->template; $twig->twig_vars['location'] = $this->template;
$twig->twig_vars['base_url_relative_frontend'] = $twig->twig_vars['base_url_relative'] ?: '/'; $twig->twig_vars['base_url_relative_frontend'] = $twig->twig_vars['base_url_relative'] ?: '/';
$twig->twig_vars['admin_route'] = trim($this->admin_route, '/'); $twig->twig_vars['admin_route'] = trim($this->admin_route, '/');
$twig->twig_vars['current_route'] = '/' . $twig->twig_vars['admin_route'] . '/' . $this->template . '/' . $this->route;
$twig->twig_vars['base_url_relative'] = $twig->twig_vars['base_url_simple'] . '/' . $twig->twig_vars['admin_route']; $twig->twig_vars['base_url_relative'] = $twig->twig_vars['base_url_simple'] . '/' . $twig->twig_vars['admin_route'];
$twig->twig_vars['current_url'] = rtrim($twig->twig_vars['base_url_relative'] . '/' . $this->template . '/' . $this->route, '/');
$theme_url = '/' . ltrim($this->grav['locator']->findResource('plugin://admin/themes/' . $this->theme, $theme_url = '/' . ltrim($this->grav['locator']->findResource('plugin://admin/themes/' . $this->theme,
false), '/'); false), '/');
$twig->twig_vars['theme_url'] = $theme_url; $twig->twig_vars['theme_url'] = $theme_url;
@@ -762,7 +764,8 @@ class AdminPlugin extends Plugin
{ {
// Special case to redirect after changing the admin route to avoid 'breaking' // Special case to redirect after changing the admin route to avoid 'breaking'
$obj = $event['object']; $obj = $event['object'];
if (null !== $obj) {
if (null !== $obj && method_exists($obj, 'blueprints')) {
$blueprint = $obj->blueprints()->getFilename(); $blueprint = $obj->blueprints()->getFilename();
if ($blueprint === 'admin/blueprints' && isset($obj->route) && $this->admin_route !== $obj->route) { if ($blueprint === 'admin/blueprints' && isset($obj->route) && $this->admin_route !== $obj->route) {

View File

@@ -1,5 +1,5 @@
name: Admin Panel name: Admin Panel
version: 1.8.1 version: 1.8.2
description: Adds an advanced administration panel to manage your site description: Adds an advanced administration panel to manage your site
icon: empire icon: empire
author: author:

View File

@@ -365,7 +365,7 @@ class Admin
$userKey = isset($credentials['username']) ? (string)$credentials['username'] : ''; $userKey = isset($credentials['username']) ? (string)$credentials['username'] : '';
$ipKey = Uri::ip(); $ipKey = Uri::ip();
$redirect = isset($post['redirect']) ? $post['redirect'] : $this->uri->route(); $redirect = $this->base . $this->route;
// Check if the current IP has been used in failed login attempts. // Check if the current IP has been used in failed login attempts.
$attempts = count($rateLimiter->getAttempts($ipKey, 'ip')); $attempts = count($rateLimiter->getAttempts($ipKey, 'ip'));
@@ -392,11 +392,9 @@ class Admin
if ($user->authorized) { if ($user->authorized) {
$event->defMessage('PLUGIN_ADMIN.LOGIN_LOGGED_IN', 'info'); $event->defMessage('PLUGIN_ADMIN.LOGIN_LOGGED_IN', 'info');
$event->defRedirect($redirect); $event->defRedirect(isset($post['redirect']) ? $post['redirect'] : $redirect);
} else { } else {
$this->session->redirect = $redirect; $this->session->redirect = $redirect;
$event->defRedirect($this->uri->route());
} }
} else { } else {
if ($user->authorized) { if ($user->authorized) {
@@ -406,7 +404,7 @@ class Admin
} }
} }
$event->defRedirect($this->uri->route()); $event->defRedirect($redirect);
$message = $event->getMessage(); $message = $event->getMessage();
if ($message) { if ($message) {

View File

@@ -2,8 +2,10 @@
namespace Grav\Plugin\Admin; namespace Grav\Plugin\Admin;
use Grav\Common\Config\Config; use Grav\Common\Config\Config;
use Grav\Common\Data\Data;
use Grav\Common\Filesystem\Folder; use Grav\Common\Filesystem\Folder;
use Grav\Common\Grav; use Grav\Common\Grav;
use Grav\Common\Media\Interfaces\MediaInterface;
use Grav\Common\Page\Media; use Grav\Common\Page\Media;
use Grav\Common\Utils; use Grav\Common\Utils;
use Grav\Common\Plugin; use Grav\Common\Plugin;
@@ -259,7 +261,7 @@ class AdminBaseController
} }
// Handle errors and breaks without proceeding further // Handle errors and breaks without proceeding further
if ($upload->file->error != UPLOAD_ERR_OK) { if ($upload->file->error !== UPLOAD_ERR_OK) {
$this->admin->json_response = [ $this->admin->json_response = [
'status' => 'error', 'status' => 'error',
'message' => sprintf($this->admin->translate('PLUGIN_ADMIN.FILEUPLOAD_UNABLE_TO_UPLOAD', null), 'message' => sprintf($this->admin->translate('PLUGIN_ADMIN.FILEUPLOAD_UNABLE_TO_UPLOAD', null),
@@ -717,9 +719,9 @@ class AdminBaseController
} else { } else {
$new_data = $files; $new_data = $files;
} }
if (isset($data['header'][$init_key])) { if ($obj->header()->{$init_key}) {
$obj->modifyHeader($init_key, $obj->modifyHeader($init_key,
array_replace_recursive([], $data['header'][$init_key], $new_data)); array_replace_recursive([], $obj->header()->{$init_key}, $new_data));
} else { } else {
$obj->modifyHeader($init_key, $new_data); $obj->modifyHeader($init_key, $new_data);
} }
@@ -744,7 +746,16 @@ class AdminBaseController
} }
$data = $this->view === 'pages' ? $this->admin->page(true) : $this->prepareData([]); $data = $this->view === 'pages' ? $this->admin->page(true) : $this->prepareData([]);
if (null === $data) {
return false;
}
if ($data instanceof Data) {
$settings = $data->blueprints()->schema()->getProperty($this->post['name']); $settings = $data->blueprints()->schema()->getProperty($this->post['name']);
} elseif (method_exists($data, 'getBlueprint')) {
$settings = $data->getBlueprint()->schema()->getProperty($this->post['name']);
}
if (isset($settings['folder'])) { if (isset($settings['folder'])) {
$folder = $settings['folder']; $folder = $settings['folder'];
@@ -754,6 +765,7 @@ class AdminBaseController
// Do not use self@ outside of pages // Do not use self@ outside of pages
if ($this->view !== 'pages' && in_array($folder, ['@self', 'self@', '@self@'])) { if ($this->view !== 'pages' && in_array($folder, ['@self', 'self@', '@self@'])) {
if (!$data instanceof MediaInterface) {
$this->admin->json_response = [ $this->admin->json_response = [
'status' => 'error', 'status' => 'error',
'message' => sprintf($this->admin->translate('PLUGIN_ADMIN.FILEUPLOAD_PREVENT_SELF', null), $folder) 'message' => sprintf($this->admin->translate('PLUGIN_ADMIN.FILEUPLOAD_PREVENT_SELF', null), $folder)
@@ -762,11 +774,15 @@ class AdminBaseController
return false; return false;
} }
$media = $data->getMedia();
} else {
// Set destination // Set destination
$folder = Folder::getRelativePath(rtrim($folder, '/')); $folder = Folder::getRelativePath(rtrim($folder, '/'));
$folder = $this->admin->getPagePathFromToken($folder); $folder = $this->admin->getPagePathFromToken($folder);
$media = new Media($folder); $media = new Media($folder);
}
$available_files = []; $available_files = [];
$metadata = []; $metadata = [];
$thumbs = []; $thumbs = [];

View File

@@ -613,12 +613,14 @@ class AdminController extends AdminBaseController
// Special handler for user data. // Special handler for user data.
if ($this->view === 'user') { if ($this->view === 'user') {
if (!$this->grav['user']->exists()) {
$this->admin->setMessage($this->admin->translate('PLUGIN_ADMIN.NO_USER_EXISTS'),'error');
return false;
}
if (!$this->admin->authorize(['admin.super', 'admin.users'])) { if (!$this->admin->authorize(['admin.super', 'admin.users'])) {
//not admin.super or admin.users // no user file or not admin.super or admin.users
if ($this->prepareData($data)->username !== $this->grav['user']->username) { if ($this->prepareData($data)->username !== $this->grav['user']->username) {
$this->admin->setMessage($this->admin->translate('PLUGIN_ADMIN.INSUFFICIENT_PERMISSIONS_FOR_TASK') . ' save.', $this->admin->setMessage($this->admin->translate('PLUGIN_ADMIN.INSUFFICIENT_PERMISSIONS_FOR_TASK') . ' save.','error');
'error');
return false; return false;
} }
} }
@@ -1687,9 +1689,16 @@ class AdminController extends AdminBaseController
return false; return false;
} }
/** @var UniformResourceLocator $locator */
$locator = $this->grav['locator'];
$path = $media->path();
if ($locator->isStream($path)) {
$path = $locator->findResource($path, true, true);
}
// Upload it // Upload it
if (!move_uploaded_file($_FILES['file']['tmp_name'], if (!move_uploaded_file($_FILES['file']['tmp_name'],
sprintf('%s/%s', $media->path(), $_FILES['file']['name'])) sprintf('%s/%s', $path, $_FILES['file']['name']))
) { ) {
$this->admin->json_response = [ $this->admin->json_response = [
'status' => 'error', 'status' => 'error',
@@ -1759,7 +1768,13 @@ class AdminController extends AdminBaseController
return false; return false;
} }
/** @var UniformResourceLocator $locator */
$locator = $this->grav['locator'];
$targetPath = $media->path() . '/' . $filename; $targetPath = $media->path() . '/' . $filename;
if ($locator->isStream($targetPath)) {
$targetPath = $locator->findResource($targetPath, true, true);
}
$fileParts = pathinfo($filename); $fileParts = pathinfo($filename);
$found = false; $found = false;

View File

@@ -441,6 +441,7 @@ PLUGIN_ADMIN:
PAGE_FILE: "Page Template" PAGE_FILE: "Page Template"
PAGE_FILE_HELP: "Page template file name, and by default the display template for this page" PAGE_FILE_HELP: "Page template file name, and by default the display template for this page"
NO_USER_ACCOUNTS: "No user accounts found, please create one first..." NO_USER_ACCOUNTS: "No user accounts found, please create one first..."
NO_USER_EXISTS: "No local user exists for this account, cannot save..."
REDIRECT_TRAILING_SLASH: "Redirect trailing slash" REDIRECT_TRAILING_SLASH: "Redirect trailing slash"
REDIRECT_TRAILING_SLASH_HELP: "Perform a 301 redirect rather than transparently handling trailing slash URIs." REDIRECT_TRAILING_SLASH_HELP: "Perform a 301 redirect rather than transparently handling trailing slash URIs."
DEFAULT_DATE_FORMAT: "Page date format" DEFAULT_DATE_FORMAT: "Page date format"

View File

@@ -1,5 +1,5 @@
import $ from 'jquery'; import $ from 'jquery';
import { config } from 'grav-config'; import { config, uri_params } from 'grav-config';
import request from '../../utils/request'; import request from '../../utils/request';
const insertTextAt = (string, index, text) => [string.slice(0, index), text, string.slice(index)].join(''); const insertTextAt = (string, index, text) => [string.slice(0, index), text, string.slice(index)].join('');
@@ -45,10 +45,11 @@ export default class FilePickerField {
let parent = field.closest('[data-grav-filepicker]'); let parent = field.closest('[data-grav-filepicker]');
let name = parent.data('name'); let name = parent.data('name');
let value = parent.data('value'); let value = parent.data('value');
let params = JSON.stringify(uri_params || '{}');
request(url, { request(url, {
method: 'post', method: 'post',
body: { name } body: { name, params }
}, (response) => { }, (response) => {
if (typeof response.files === 'undefined') { if (typeof response.files === 'undefined') {
return; return;

View File

@@ -162,7 +162,6 @@ export default class FilesField {
} }
getURI() { getURI() {
console.log(this.container.data('mediaUri'));
return this.container.data('mediaUri') || ''; return this.container.data('mediaUri') || '';
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -909,16 +909,16 @@ form {
} }
.form-fieldset { .form-fieldset {
background-color: #f7f7f7; background-color: darken($content-bg, 1%);
border: 2px solid #e1e1e1; border: 1px solid $form-border;
} }
.form-fieldset--label { .form-fieldset--label {
background-color: #f3f3f3; background-color: darken($content-bg, 4%);
&:hover, &:hover,
.form-fieldset input:checked + & { .form-fieldset input:checked + & {
background-color: #eee; background-color: darken($content-bg, 6%);
} }
} }
#admin-main { #admin-main {

View File

@@ -604,7 +604,7 @@ textarea.frontmatter {
letter-spacing: normal; letter-spacing: normal;
} }
.form-fieldset { .form-fieldset {
margin: 1rem 2rem; margin: 1rem 1.5rem;
} }
.form-fieldset--label { .form-fieldset--label {

View File

@@ -45,16 +45,18 @@
{% if field.max is defined and not field.selectunique %}data-max="{{ field.max }}"{% endif %} {% if field.max is defined and not field.selectunique %}data-max="{{ field.max }}"{% endif %}
> >
{% if fieldControls in ['top', 'both'] %} {% if fieldControls in ['top', 'both'] %}
<div class="collection-actions{{ not value|length ? ' hidden' : '' }}"> <div class="collection-actions">
{% if collapsible %}
<button class="button" type="button" data-action="expand_all" <button class="button" type="button" data-action="expand_all"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-chevron-circle-down"></i> {{ "PLUGIN_ADMIN.EXPAND_ALL"|e|tu }}</button> {% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-chevron-circle-down"></i> {{ "PLUGIN_ADMIN.EXPAND_ALL"|e|tu }}</button>
<button class="button" type="button" data-action="collapse_all" <button class="button" type="button" data-action="collapse_all"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-chevron-circle-right"></i> {{ "PLUGIN_ADMIN.COLLAPSE_ALL"|e|tu }}</button> {% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-chevron-circle-right"></i> {{ "PLUGIN_ADMIN.COLLAPSE_ALL"|e|tu }}</button>
{% endif %}
{% if field.sortby %} {% if field.sortby %}
<button class="button{{ not value|length ? ' hidden' : '' }}" type="button" data-action="sort" data-action-sort="{{ field.sortby }}" data-action-sort-dir="{{ field.sortby_dir|default('asc') }}" <button class="button{{ not value|length ? ' hidden' : '' }}" type="button" data-action="sort" data-action-sort="{{ field.sortby }}" data-action-sort-dir="{{ field.sortby_dir|default('asc') }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-sort-amount-{{ field.sortby_dir|default('asc') }}"></i> {{ btnSortLabel|e|tu }} '{{ field.sortby }}'</button> {% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-sort-amount-{{ field.sortby_dir|default('asc') }}"></i> {{ btnSortLabel|e|tu }} '{{ field.sortby }}'</button>
{% endif %} {% endif %}
<button class="button" type="button" data-action="add" data-action-add="top" <button class="button" type="button" data-action="add" data-action-add="bottom"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-plus"></i> {{ btnLabel|e|tu }}</button> {% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-plus"></i> {{ btnLabel|e|tu }}</button>
</div> </div>
{% endif %} {% endif %}

View File

@@ -1,7 +1,7 @@
{% if authorize(['admin.pages', 'admin.super']) %} {% if authorize(['admin.pages', 'admin.super']) %}
<div id="latest"> <div id="latest">
<div class="button-bar"> <div class="button-bar">
<a class="button" href="{{ uri.route(true) }}/pages"><i class="fa fa-fw fa-file-text-o"></i>{{ "PLUGIN_ADMIN.MANAGE_PAGES"|tu }}</a> <a class="button" href="{{ base_url_relative }}/pages"><i class="fa fa-fw fa-file-text-o"></i>{{ "PLUGIN_ADMIN.MANAGE_PAGES"|tu }}</a>
</div> </div>
<h1>{{ "PLUGIN_ADMIN.LATEST_PAGE_UPDATES"|tu }}</h1> <h1>{{ "PLUGIN_ADMIN.LATEST_PAGE_UPDATES"|tu }}</h1>
<table> <table>

View File

@@ -15,7 +15,7 @@
{% block integration %}{% endblock %} {% block integration %}{% endblock %}
{% set redirect = redirect ?: uri.route(false) %} {% set redirect = redirect ?: '/' ~ admin_route ~ '/' ~ admin.route %}
<form method="post" action="{{ base_url_relative }}"> <form method="post" action="{{ base_url_relative }}">
<div class="padding"> <div class="padding">