mirror of
https://github.com/processwire/processwire.git
synced 2025-08-15 03:05:26 +02:00
Add support for $template->pagefileSecure option configured per-template. This also expands upon what $config->pagefileSecure could do before, now supporting the ability to secure Pagefiles even for public pages when appropriate.
This commit is contained in:
@@ -149,6 +149,7 @@
|
||||
*
|
||||
* @property string $userAuthSalt Salt generated at install time to be used as a secondary/non-database salt for the password system. #pw-group-session
|
||||
* @property string $userAuthHashType Default is 'sha1' - used only if Blowfish is not supported by the system. #pw-group-session
|
||||
* @property string $tableSalt #pw-group-system Additional hash for other (non-authentication) purposes, present only on installations start from 3.0.164+. #pw-group-system
|
||||
*
|
||||
* @property bool $internal This is automatically set to FALSE when PW is externally bootstrapped. #pw-group-runtime
|
||||
* @property bool $external This is automatically set to TRUE when PW is externally bootstrapped. #pw-internal
|
||||
|
@@ -4107,6 +4107,26 @@ class Page extends WireData implements \Countable, WireMatchable {
|
||||
return $this->filesManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this Page use secure Pagefiles?
|
||||
*
|
||||
* See also `$template->pagefileSecure` and `$config->pagefileSecure` which determine the return value.
|
||||
*
|
||||
* #pw-group-files
|
||||
*
|
||||
* @return bool|null Returns boolean true if yes, false if no, or null if not known
|
||||
* @since 3.0.166
|
||||
*
|
||||
*/
|
||||
public function secureFiles() {
|
||||
if($this->wire()->config->pagefileSecure && !$this->isPublic()) return true;
|
||||
if(!$this->template) return null;
|
||||
$value = $this->template->pagefileSecure;
|
||||
if($value < 1) return false; // 0: disabled
|
||||
if($value > 1) return true; // 2: files always secure
|
||||
return !$this->isPublic(); // 1: secure only if page not public
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the page have a files path for storing files?
|
||||
*
|
||||
|
@@ -62,6 +62,14 @@ class PagefilesManager extends Wire {
|
||||
const metaFileName = '.pw';
|
||||
*/
|
||||
|
||||
/**
|
||||
* Count of renamed paths when changing between pagefileSecure and non-pagefileSecure
|
||||
*
|
||||
* @var int
|
||||
*
|
||||
*/
|
||||
static $numRenamedPaths = 0;
|
||||
|
||||
/**
|
||||
* Reference to the Page object this PagefilesManager is managing
|
||||
*
|
||||
@@ -528,7 +536,7 @@ class PagefilesManager extends Wire {
|
||||
*/
|
||||
static public function _path(Page $page, $extended = false) {
|
||||
|
||||
$config = $page->wire('config');
|
||||
$config = $page->wire()->config;
|
||||
$path = $config->paths->files;
|
||||
|
||||
$securePrefix = $config->pagefileSecurePathPrefix;
|
||||
@@ -541,39 +549,39 @@ class PagefilesManager extends Wire {
|
||||
$publicPath = $path . $page->id . '/';
|
||||
$securePath = $path . $securePrefix . $page->id . '/';
|
||||
}
|
||||
/* @todo 3.0.150:
|
||||
$filesPublic = true;
|
||||
if(!$page->isPublic()) {
|
||||
// page not publicly viewable to all, check if files are public or not
|
||||
if($config->pagefileSecure) {
|
||||
$filesPublic = false;
|
||||
} else if($page->template && $page->template->pagefileSecure) {
|
||||
$filesPublic = false; // 3.0.150+
|
||||
}
|
||||
}
|
||||
|
||||
if($filesPublic) {
|
||||
*/
|
||||
if($page->isPublic() || !$config->pagefileSecure) {
|
||||
|
||||
$secureFiles = $page->secureFiles();
|
||||
|
||||
if($secureFiles === false) {
|
||||
// use the public path, renaming a secure path to public if it exists
|
||||
if(is_dir($securePath) && !is_dir($publicPath)) {
|
||||
@rename($securePath, $publicPath);
|
||||
if(is_dir($securePath) && !is_dir($publicPath) && $secureFiles !== null) {
|
||||
$page->wire()->files->rename($securePath, $publicPath);
|
||||
self::$numRenamedPaths++;
|
||||
}
|
||||
$filesPath = $publicPath;
|
||||
|
||||
} else if($secureFiles === null) {
|
||||
$filesPath = $publicPath;
|
||||
|
||||
} else {
|
||||
// use the secure path, renaming the public to secure if it exists
|
||||
$hasSecurePath = is_dir($securePath);
|
||||
if(is_dir($publicPath) && !$hasSecurePath) {
|
||||
@rename($publicPath, $securePath);
|
||||
$page->wire()->files->rename($publicPath, $securePath);
|
||||
self::$numRenamedPaths++;
|
||||
|
||||
} else if(!$hasSecurePath && self::defaultSecurePathPrefix != $securePrefix) {
|
||||
// we track this just in case the prefix was newly added to config.php, this prevents
|
||||
// losing track of the original directories
|
||||
$securePath2 = $extended ? $path . self::_dirExtended($page->id, self::defaultSecurePathPrefix) : $path . self::defaultSecurePathPrefix . $page->id . '/';
|
||||
if($extended) {
|
||||
$securePath2 = $path . self::_dirExtended($page->id, self::defaultSecurePathPrefix);
|
||||
} else {
|
||||
$securePath2 = $path . self::defaultSecurePathPrefix . $page->id . '/';
|
||||
}
|
||||
if(is_dir($securePath2)) {
|
||||
// if the secure path prefix has been changed from undefined to defined
|
||||
@rename($securePath2, $securePath);
|
||||
$page->wire()->files->rename($securePath2, $securePath);
|
||||
self::$numRenamedPaths++;
|
||||
}
|
||||
}
|
||||
$filesPath = $securePath;
|
||||
@@ -587,6 +595,22 @@ class PagefilesManager extends Wire {
|
||||
return $filesPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get quantity of renamed paths to to pagefileSecure changes
|
||||
*
|
||||
* #pw-internal
|
||||
*
|
||||
* @param bool $reset Also reset to 0?
|
||||
* @return int
|
||||
* @since 3.0.166
|
||||
*
|
||||
*/
|
||||
static public function numRenamedPaths($reset = false) {
|
||||
$num = self::$numRenamedPaths;
|
||||
if($reset) self::$numRenamedPaths = 0;
|
||||
return $num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the directory name (after /site/assets/files/)
|
||||
*
|
||||
|
@@ -81,7 +81,7 @@
|
||||
* @property int|bool $noAppendTemplateFile Disabe automatic append of $config->appendTemplateFile (if in use). #pw-group-files
|
||||
* @property string $prependFile File to prepend to template file (separate from $config->prependTemplateFile). #pw-group-files
|
||||
* @property string $appendFile File to append to template file (separate from $config->appendTemplateFile). #pw-group-files
|
||||
* @property bool $pagefileSecure Use secure pagefiles for pages using this template? (3.0.150+) #pw-group-files
|
||||
* @property int $pagefileSecure Use secure pagefiles for pages using this template? 0=No/not set, 1=Yes (for non-public pages), 2=Always (3.0.166+) #pw-group-files
|
||||
*
|
||||
* Page Editor
|
||||
*
|
||||
@@ -272,7 +272,7 @@ class Template extends WireData implements Saveable, Exportable {
|
||||
'noAppendTemplateFile' => 0, // disable automatic inclusion of $config->appendTemplateFile
|
||||
'prependFile' => '', // file to prepend (relative to /site/templates/)
|
||||
'appendFile' => '', // file to append (relative to /site/templates/)
|
||||
'pagefileSecure' => false, // secure files connected with page? (3.0.150+)
|
||||
'pagefileSecure' => 0, // secure files connected with page? 0=Off, 1=Yes for unpub/non-public pages, 2=Always (3.0.166+)
|
||||
'tabContent' => '', // label for the Content tab (if different from 'Content')
|
||||
'tabChildren' => '', // label for the Children tab (if different from 'Children')
|
||||
'nameLabel' => '', // label for the "name" property of the page (if something other than "Name")
|
||||
@@ -1376,6 +1376,23 @@ class Template extends WireData implements Saveable, Exportable {
|
||||
return $this->wire('templates')->getPageClass($this, $withNamespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that all file asset paths are consistent with current pagefileSecure setting and access control
|
||||
*
|
||||
* #pw-internal
|
||||
*
|
||||
* @return int Returns quantity of renamed paths, or 0 if all is in order
|
||||
* @since 3.0.166
|
||||
*
|
||||
*/
|
||||
public function checkPagefileSecure() {
|
||||
PagefilesManager::numRenamedPaths(true);
|
||||
foreach($this->wire()->pages->findMany("template=$this, include=all") as $p) {
|
||||
PagefilesManager::_path($p);
|
||||
}
|
||||
return PagefilesManager::numRenamedPaths(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the icon to use with this template
|
||||
*
|
||||
|
@@ -266,7 +266,7 @@ class PagePermissions extends WireData implements Module {
|
||||
} else if($this->wire('page') && $this->wire('page')->process == 'ProcessProfile') {
|
||||
// user editing themself in ProcessProfile, when process not yet established
|
||||
return true;
|
||||
} else if($process == 'ProcessPageView' && $config->pagefileSecure && $options['viewable']) {
|
||||
} else if($process == 'ProcessPageView' && $page->secureFiles() && $options['viewable']) {
|
||||
// user is viewing a file that is part of their User page when pagefileSecure mode active
|
||||
return $process->getResponseType() == ProcessPageView::responseTypeFile;
|
||||
}
|
||||
@@ -481,6 +481,28 @@ class PagePermissions extends WireData implements Module {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is given file viewable?
|
||||
*
|
||||
* It is assumed that you have already determined the Page is viewable.
|
||||
*
|
||||
* @param Page $page
|
||||
* @param Pagefile|string $pagefile
|
||||
* @return bool|null Returns bool, or null if not known
|
||||
* @since 3.0.166
|
||||
*
|
||||
*/
|
||||
protected function fileViewable(Page $page, $pagefile) {
|
||||
if($this->wire()->user->isSuperuser()) return true;
|
||||
if(!$pagefile instanceof Pagefile) {
|
||||
$pagefile = $page->hasFile(basename($pagefile), array('getPagefile' => true));
|
||||
if(!$pagefile) return null;
|
||||
}
|
||||
$field = $pagefile->field;
|
||||
if(!$field) return null;
|
||||
return $this->fieldViewable($page, $field, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the given field editable by the current user in their user profile?
|
||||
*
|
||||
@@ -511,6 +533,11 @@ class PagePermissions extends WireData implements Module {
|
||||
* - Optionally specify Language object or language name as first argument to check if viewable
|
||||
* in that language (requires LanguageSupportPageNames module).
|
||||
* - Optionally specify boolean false as first or second argument to bypass template filename check.
|
||||
* - Optionally specify a Pagefile object or file basename to check if file is viewable. (3.0.166+)
|
||||
*
|
||||
* Returns boolean true or false. If given a Pagefile or file basename, it can also return null if
|
||||
* the Page itself is viewable but the file did not map to something we recognize as access controlled,
|
||||
* like a file basename that isn’t present in any file fields on the page.
|
||||
*
|
||||
* @param HookEvent $event
|
||||
*
|
||||
@@ -520,11 +547,12 @@ class PagePermissions extends WireData implements Module {
|
||||
/** @var Page $page */
|
||||
$page = $event->object;
|
||||
$viewable = true;
|
||||
$user = $this->wire('user');
|
||||
$user = $this->wire()->user;
|
||||
$arg0 = $event->arguments(0);
|
||||
$arg1 = $event->arguments(1);
|
||||
$field = null; // field name or Field object, if specified as arg0
|
||||
$checkFile = true; // return false if template filename doesn't exist
|
||||
$checkTemplateFile = true; // return false if template filename doesn't exist
|
||||
$pagefile = null;
|
||||
$status = $page->status;
|
||||
|
||||
// allow specifying User instance as argument 0
|
||||
@@ -533,16 +561,21 @@ class PagePermissions extends WireData implements Module {
|
||||
if($arg0 instanceof User) {
|
||||
// user specified
|
||||
$user = $arg0;
|
||||
} else if($arg0 instanceof Pagefile || (is_string($arg0) && strpos($arg0, '.'))) {
|
||||
// Pagefile or file basename
|
||||
$pagefile = $arg0;
|
||||
$checkTemplateFile = false;
|
||||
} else if($arg0 instanceof Field || is_string($arg0)) {
|
||||
// field name, Field object or language name specified
|
||||
// @todo: prevent possible collision of field name and language name
|
||||
$field = $arg0;
|
||||
$checkFile = false;
|
||||
$checkTemplateFile = false;
|
||||
}
|
||||
}
|
||||
|
||||
if($arg0 === false || $arg1 === false) {
|
||||
// bypass template filename check
|
||||
$checkFile = false;
|
||||
$checkTemplateFile = false;
|
||||
}
|
||||
|
||||
// if page has corrupted status, this need not affect viewable access
|
||||
@@ -552,7 +585,7 @@ class PagePermissions extends WireData implements Module {
|
||||
if($status >= Page::statusUnpublished) {
|
||||
// unpublished pages are not viewable, but see override below this if/else statement
|
||||
$viewable = false;
|
||||
} else if(!$page->template || ($checkFile && !$page->template->filenameExists())) {
|
||||
} else if(!$page->template || ($checkTemplateFile && !$page->template->filenameExists())) {
|
||||
// template file does not exist
|
||||
$viewable = false;
|
||||
} else if($user->isSuperuser()) {
|
||||
@@ -574,11 +607,13 @@ class PagePermissions extends WireData implements Module {
|
||||
|
||||
// if the page is editable by the current user, force it to be viewable (if not viewable due to being unpublished)
|
||||
if(!$viewable && !$user->isGuest() && ($status & Page::statusUnpublished)) {
|
||||
if($page->editable() && (!$checkFile || $page->template->filenameExists())) $viewable = true;
|
||||
if($page->editable() && (!$checkTemplateFile || $page->template->filenameExists())) $viewable = true;
|
||||
}
|
||||
|
||||
if($field && $viewable) {
|
||||
$viewable = $this->fieldViewable($page, $field, false);
|
||||
} else if($pagefile && $viewable) {
|
||||
$viewable = $this->fileViewable($page, $pagefile);
|
||||
}
|
||||
|
||||
$event->return = $viewable;
|
||||
|
@@ -29,7 +29,7 @@ class ProcessPageView extends Process {
|
||||
'version' => 104,
|
||||
'permanent' => true,
|
||||
'permission' => 'page-view',
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -372,8 +372,7 @@ class ProcessPageView extends Process {
|
||||
$numParts = substr_count($it, '/');
|
||||
if($numParts > $config->maxUrlDepth) return null;
|
||||
|
||||
// if($this->isSecurePagefileUrl($it)) { // @todo replace next line with this in 3.0.150
|
||||
if($config->pagefileSecure) {
|
||||
if($this->pagefileSecurePossible($it)) {
|
||||
$page = $this->checkRequestFile($it);
|
||||
if(is_object($page)) {
|
||||
$this->responseType = self::responseTypeFile;
|
||||
@@ -482,10 +481,8 @@ class ProcessPageView extends Process {
|
||||
*/
|
||||
protected function checkRequestFile(&$it) {
|
||||
|
||||
/** @var Config $config */
|
||||
$config = $this->wire('config');
|
||||
/** @var Pages $pages */
|
||||
$pages = $this->wire('pages');
|
||||
$config = $this->wire()->config;
|
||||
$pages = $this->wire()->pages;
|
||||
|
||||
// request with url to root (applies only if site runs from subdirectory)
|
||||
$itRoot = rtrim($config->urls->root, '/') . $it;
|
||||
@@ -501,11 +498,14 @@ class ProcessPageView extends Process {
|
||||
$idPath = trim($matches[1], '/');
|
||||
$file = trim($matches[2], '.');
|
||||
|
||||
if(!strpos($file, '.')) return $pages->newNullPage();
|
||||
|
||||
if(!ctype_digit("$idPath")) {
|
||||
// extended paths where id separated by slashes, i.e. 1/2/3/4
|
||||
if($config->pagefileExtendedPaths) {
|
||||
// allow extended paths
|
||||
$idPath = str_replace('/', '', $matches[1]);
|
||||
if(!ctype_digit("$idPath")) return $pages->newNullPage();
|
||||
} else {
|
||||
// extended paths not allowed
|
||||
return $pages->newNullPage();
|
||||
@@ -525,7 +525,7 @@ class ProcessPageView extends Process {
|
||||
return $pages->newNullPage();
|
||||
|
||||
} else if(!preg_match('/^[a-zA-Z0-9][-_a-zA-Z0-9]+$/', $subdir)) {
|
||||
// subdirectory nat in expected format
|
||||
// subdirectory not in expected format
|
||||
return $pages->newNullPage();
|
||||
}
|
||||
|
||||
@@ -702,6 +702,7 @@ class ProcessPageView extends Process {
|
||||
|
||||
if($this->requestFile) {
|
||||
// if a file was requested, we still allow view even if page doesn't have template file
|
||||
if($page->viewable($this->requestFile) === false) return null;
|
||||
if($page->viewable(false)) return $page;
|
||||
// if($page->editable()) return $page;
|
||||
if($this->checkAccessDelegated($page)) return $page;
|
||||
@@ -863,29 +864,37 @@ class ProcessPageView extends Process {
|
||||
* If the page is public, then it just does a 301 redirect to the file.
|
||||
*
|
||||
* @param Page $page
|
||||
* @param string $basename
|
||||
* @param string $basename
|
||||
* @param array $options
|
||||
* @throws Wire404Exception
|
||||
*
|
||||
*/
|
||||
protected function ___sendFile($page, $basename) {
|
||||
protected function ___sendFile($page, $basename, array $options = array()) {
|
||||
|
||||
$err = 'File not found';
|
||||
|
||||
// use the static hasPath first to make sure this page actually has a files directory
|
||||
// this ensures one isn't automatically created when we call $page->filesManager->path below
|
||||
if(!PagefilesManager::hasPath($page)) throw new Wire404Exception($err, Wire404Exception::codeFile);
|
||||
|
||||
$filename = $page->filesManager->path() . $basename;
|
||||
if(!is_file($filename)) throw new Wire404Exception($err, Wire404Exception::codeFile);
|
||||
|
||||
if($page->isPublic()) {
|
||||
// deprecated, only necessary for method 2 in checkRequestFile
|
||||
$this->wire('session')->redirect($page->filesManager->url() . $basename);
|
||||
|
||||
} else {
|
||||
$options = array('exit' => false);
|
||||
wireSendFile($filename, $options);
|
||||
if(!$page->hasFilesPath()) {
|
||||
throw new Wire404Exception($err, Wire404Exception::codeFile);
|
||||
}
|
||||
|
||||
$filename = $page->filesPath() . $basename;
|
||||
|
||||
if(!file_exists($filename)) {
|
||||
throw new Wire404Exception($err, Wire404Exception::codeFile);
|
||||
}
|
||||
|
||||
if(!$page->secureFiles()) {
|
||||
// if file is not secured, redirect to it
|
||||
// (potentially deprecated, only necessary for method 2 in checkRequestFile)
|
||||
$this->wire()->session->redirect($page->filesManager->url() . $basename);
|
||||
return;
|
||||
}
|
||||
|
||||
// options for WireHttp::sendFile
|
||||
$defaults = array('exit' => false);
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
$this->wire()->files->send($filename, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -971,10 +980,11 @@ class ProcessPageView extends Process {
|
||||
*
|
||||
* @param string $url
|
||||
* @return bool
|
||||
* @todo enable in 3.0.150
|
||||
* @since 3.0.166
|
||||
*
|
||||
protected function isSecurePagefileUrl($url) {
|
||||
$config = $this->wire('config');
|
||||
*/
|
||||
protected function pagefileSecurePossible($url) {
|
||||
$config = $this->wire()->config;
|
||||
|
||||
// if URL does not start from root, prepend root
|
||||
if(strpos($url, $config->urls->root) !== 0) $url = $config->urls->root . ltrim($url, '/');
|
||||
@@ -987,7 +997,7 @@ class ProcessPageView extends Process {
|
||||
|
||||
// check if any templates allow pagefileSecure option
|
||||
$allow = false;
|
||||
foreach($this->wire('templates') as $template) {
|
||||
foreach($this->wire()->templates as $template) {
|
||||
if(!$template->pagefileSecure) continue;
|
||||
$allow = true;
|
||||
break;
|
||||
@@ -996,7 +1006,6 @@ class ProcessPageView extends Process {
|
||||
// if at least one template supports pagefileSecure option we will return true here
|
||||
return $allow;
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
@@ -684,6 +684,7 @@ class ProcessTemplate extends Process {
|
||||
$t->add($this->buildEditFormAccess($template));
|
||||
$overrides = $this->buildEditFormAccessOverrides($template);
|
||||
if($overrides) $t->add($overrides);
|
||||
$t->add($this->buildEditFormAccessFiles($template));
|
||||
$form->add($t);
|
||||
|
||||
$t = $this->wire(new InputfieldWrapper());
|
||||
@@ -1246,6 +1247,7 @@ class ProcessTemplate extends Process {
|
||||
$form = $this->wire(new InputfieldWrapper());
|
||||
/** @var Languages|null $languages */
|
||||
$languages = $this->wire('languages');
|
||||
$advanced = $this->wire()->config->advanced;
|
||||
|
||||
// --------------------
|
||||
|
||||
@@ -1392,7 +1394,7 @@ class ProcessTemplate extends Process {
|
||||
$field->attr('name', 'noChangeTemplate');
|
||||
$field->label = $this->_("Don't allow pages to change their template?");
|
||||
$field->description = $this->_("When checked, pages using this template will be unable to change to another template."); // noChangeTemplate option, description
|
||||
if($this->wire('config')->advanced) $field->notes = 'API: $template->noChangeTemplate = 1; // ' . $label0;
|
||||
if($advanced) $field->notes = 'API: $template->noChangeTemplate = 1; // ' . $label0;
|
||||
|
||||
$field->attr('value', 1);
|
||||
if($template->noChangeTemplate) {
|
||||
@@ -1409,7 +1411,7 @@ class ProcessTemplate extends Process {
|
||||
$field->attr('name', 'noUnpublish');
|
||||
$field->label = $this->_("Don't allow unpublished pages");
|
||||
$field->description = $this->_("When checked, pages using this template may only exist in a published state and may not be unpublished."); // noUnpublish option, description
|
||||
if($this->wire('config')->advanced) $field->notes = 'API: $template->noUnpublish = 1; // ' . $label0;
|
||||
if($advanced) $field->notes = 'API: $template->noUnpublish = 1; // ' . $label0;
|
||||
|
||||
$field->attr('value', 1);
|
||||
if($template->noUnpublish) {
|
||||
@@ -1426,7 +1428,7 @@ class ProcessTemplate extends Process {
|
||||
$field->attr('name', 'allowChangeUser');
|
||||
$field->label = $this->_("Allow the 'created user' to be changed on pages?");
|
||||
$field->description = $this->_("When checked, pages using this template will have an option to change the 'created by user' (for superusers only). It will also enable the \$page->createdUser or \$page->created_users_id fields to be saved via the API."); // allowChangeUser option, description
|
||||
if($this->wire('config')->advanced) $field->notes = 'API: $template->allowChangeUser = 1; // ' . $label0;
|
||||
if($advanced) $field->notes = 'API: $template->allowChangeUser = 1; // ' . $label0;
|
||||
|
||||
$field->attr('value', 1);
|
||||
if($template->allowChangeUser) {
|
||||
@@ -1443,7 +1445,7 @@ class ProcessTemplate extends Process {
|
||||
$field->attr('name', 'noMove');
|
||||
$field->label = $this->_("Don't allow pages to be moved?");
|
||||
$field->description = $this->_("If you want to prevent pages using this template from being moved (changing parent) then check this box."); // noMove option, description
|
||||
if($this->wire('config')->advanced) $field->notes = 'API: $template->noMove = 1; // ' . $label0;
|
||||
if($advanced) $field->notes = 'API: $template->noMove = 1; // ' . $label0;
|
||||
|
||||
$field->attr('value', 1);
|
||||
if($template->noMove) {
|
||||
@@ -1461,7 +1463,7 @@ class ProcessTemplate extends Process {
|
||||
$field->attr('name', 'noLang');
|
||||
$field->label = $this->_("Disable multi-language support for this template?");
|
||||
$field->description = $this->_("When checked, pages using this template will only use the default language.");
|
||||
if($this->wire('config')->advanced) $field->notes = 'API: $template->noLang = 1; // ' . $label0;
|
||||
if($advanced) $field->notes = 'API: $template->noLang = 1; // ' . $label0;
|
||||
|
||||
$field->attr('value', 1);
|
||||
if($template->noLang) {
|
||||
@@ -2128,10 +2130,40 @@ class ProcessTemplate extends Process {
|
||||
$field->attr('value', $template->noInherit ? 1 : 0);
|
||||
$fieldset->add($field);
|
||||
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the "pagefileSecure" field for the "access" tab
|
||||
*
|
||||
* @param Template $template
|
||||
* @return InputfieldRadios
|
||||
*
|
||||
*/
|
||||
protected function buildEditFormAccessFiles(Template $template) {
|
||||
|
||||
/** @var InputfieldRadios $f */
|
||||
$f = $this->modules->get('InputfieldRadios');
|
||||
$f->attr('id+name', 'pagefileSecure');
|
||||
$f->label = $this->_('Prevent direct access to file assets owned by pages using this template?');
|
||||
$f->icon = 'download';
|
||||
$f->description =
|
||||
$this->_('When direct access to a file in [u]/site/assets/files/[/u] is blocked, ProcessWire can manage delivery of the file, rather than Apache.') . ' ' .
|
||||
$this->_('This enables the file to be access controlled in the same manner as the page that owns it, while still using the original file URL.') . ' ' .
|
||||
$this->_('Note that it takes more overhead to deliver a file this way, so only choose the “Yes always” option if you need it.');
|
||||
$f->notes =
|
||||
$this->_('Always test that the access control is working how you expect by attempting to access the protected file(s) in your browser.') . ' ' .
|
||||
$this->_('Do this for when you expect to have access (logged-in) and when you do not (logged-out).');
|
||||
$f->addOption(0, $this->_('No') . ' ' .
|
||||
'[span.detail] ' . $this->_('(uses site-wide configuration instead)') . ' [/span]');
|
||||
$f->addOption(1, $this->_('Yes when page is unpublished, in the trash, or not publicly accessible'));
|
||||
$f->addOption(2, $this->_('Yes always, regardless of page status or access control'));
|
||||
$f->val((int) $template->pagefileSecure);
|
||||
if(!$template->pagefileSecure) $f->collapsed = Inputfield::collapsedYes;
|
||||
|
||||
return $f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the "roles" field for "access" tab in edit form
|
||||
*
|
||||
@@ -2455,6 +2487,9 @@ class ProcessTemplate extends Process {
|
||||
$template->altFilename = basename($form->get('altFilename')->attr('value'), "." . $config->templateExtension);
|
||||
$template->guestSearchable = (int) $form->get('guestSearchable')->attr('value');
|
||||
$template->noInherit = (int) $form->get('noInherit')->attr('value') ? 1 : 0;
|
||||
|
||||
$pagefileSecurePrev = (int) $template->pagefileSecure;
|
||||
$template->pagefileSecure = (int) $input->post('pagefileSecure');
|
||||
|
||||
$pageLabelField = $form->get('pageLabelField')->attr('value');
|
||||
if(strpos($pageLabelField, '{') !== false && strpos($pageLabelField, '}')) {
|
||||
@@ -2666,6 +2701,23 @@ class ProcessTemplate extends Process {
|
||||
}
|
||||
unset($cloneTemplateName, $_cloneTemplateName);
|
||||
}
|
||||
|
||||
// change to the pagefileSecure setting
|
||||
if($pagefileSecurePrev !== $template->pagefileSecure) {
|
||||
$findSelector = "templates_id=$template->id, include=all";
|
||||
$qty = $this->wire()->pages->count($findSelector);
|
||||
if($qty < 1000) {
|
||||
$qty = $template->checkPagefileSecure();
|
||||
$this->message(sprintf($this->_('Renamed %d page file path(s) for change to secure files option'), $qty), Notice::noGroup);
|
||||
} else {
|
||||
$this->warning(
|
||||
sprintf($this->_('Your change to the secure files option will be applied as file/image fields on each of the %d affected pages are accessed.'), $qty) . ' ' .
|
||||
$this->_('Note that this may take some time. To apply to all now, execute the following API code from a template file:') . ' ' .
|
||||
"`\$templates->get('$template->name')->checkPagefileSecure();`",
|
||||
Notice::noGroup
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if(!$redirectUrl) $redirectUrl = "edit?id={$template->id}";
|
||||
$session->redirect($redirectUrl);
|
||||
|
Reference in New Issue
Block a user