1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-09 00:06:55 +02:00

Update ProcessModule so that module installation options are now configurable from new $config->moduleInstall array. Plus update in-module instructions to describe how to install a module manually.

This commit is contained in:
Ryan Cramer
2020-07-24 14:57:30 -04:00
parent 380583a92c
commit dd15aa9adb
6 changed files with 289 additions and 85 deletions

View File

@@ -1189,7 +1189,30 @@ $config->moduleServiceURL = 'https://modules.processwire.com/export-json/';
* @var string * @var string
* *
*/ */
$config->moduleServiceKey = (__NAMESPACE__ ? 'pw300' : 'pw280'); $config->moduleServiceKey = 'pw301';
/**
* Allowed module installation options (in admin)
*
* Module installation options you want to be available from the admin Modules > Install tab.
* For any of the options below, specify boolean `true` to allow, `false` to disallow, or
* specify string `'debug'` to allow only when ProcessWire is in debug mode.
*
* - `directory`: Allow installation or upgrades from ProcessWire modules directory?
* - `upload`: Allow installation by file upload?
* - `download`: Allow installation by file download from URL?
*
* @todo consider whether the 'directory' option should also be limited to 'debug' only.
*
* @var array
* @since 3.0.163
*
*/
$config->moduleInstall = array(
'directory' => true, // allow install from ProcessWire modules directory?
'upload' => 'debug', // allow install by module file upload?
'download' => 'debug', // allow install by download from URL?
);
/** /**
* Substitute modules * Substitute modules

View File

@@ -130,6 +130,7 @@
* @property string $moduleServiceKey API key for modules web service #pw-group-modules * @property string $moduleServiceKey API key for modules web service #pw-group-modules
* @property bool $moduleCompile Allow use of compiled modules? #pw-group-modules * @property bool $moduleCompile Allow use of compiled modules? #pw-group-modules
* @property array $wireMail Default WireMail module settings. #pw-group-modules * @property array $wireMail Default WireMail module settings. #pw-group-modules
* @property array $moduleInstall Admin module install options you allow. #pw-group-modules
* *
* @property array $substituteModules Associative array with names of substitute modules for when requested module doesn't exist #pw-group-modules * @property array $substituteModules Associative array with names of substitute modules for when requested module doesn't exist #pw-group-modules
* @property array $logs Additional core logs to keep #pw-group-admin * @property array $logs Additional core logs to keep #pw-group-admin

View File

@@ -6,7 +6,7 @@ $(document).ready(function() {
var $btn = $(".install_" + name + ":visible"); var $btn = $(".install_" + name + ":visible");
var disabled = $btn.attr('disabled'); var disabled = $btn.attr('disabled');
if($btn.size()) { if($btn.length) {
$btn.effect('highlight', 1000); $btn.effect('highlight', 1000);
} else { } else {
var color = $(this).css('color'); var color = $(this).css('color');
@@ -52,7 +52,8 @@ $(document).ready(function() {
}); });
$("#Inputfield_new_seconds").change(function() { $("#Inputfield_new_seconds").change(function() {
$(this).parents('form').submit(); $('#submit_check').removeAttr('hidden').click();
$(this).closest('form').submit();
}); });
$("#wrap_upload_module").removeClass('InputfieldItemList'); $("#wrap_upload_module").removeClass('InputfieldItemList');

View File

@@ -1 +1 @@
$(document).ready(function(){$(".not_installed").parent("a").css("opacity",0.6).click(function(){var b=$(this).children(".not_installed").attr("data-name");var d=$(".install_"+b+":visible");var c=d.attr("disabled");if(d.size()){d.effect("highlight",1000)}else{var a=$(this).css("color");$(this).closest("tr").find(".requires").attr("data-color",$(this).css("color")).css("color",a).effect("highlight",1000)}return false});$("button.ProcessModuleSettings").click(function(){var a=$(this).parents("tr").find(".ConfigurableModule").parent("a");window.location.href=a.attr("href")+"&collapse_info=1"});if($("#modules_form").length>0){$("#modules_form").WireTabs({items:$(".Inputfields li.WireTab"),rememberTabs:true})}$("select.modules_section_select").change(function(){var b=$(this).val();var a=$(this).parent("p").siblings(".modules_section");if(b==""){a.show()}else{a.hide();a.filter(".modules_"+b).show()}document.cookie=$(this).attr("name")+"="+b;return true}).change();$(document).on("click","#head_button a",function(){document.cookie="WireTabs=tab_new_modules";return true});$("#Inputfield_new_seconds").change(function(){$(this).parents("form").submit()});$("#wrap_upload_module").removeClass("InputfieldItemList")}); $(document).ready(function(){$(".not_installed").parent("a").css("opacity",.6).click(function(){var name=$(this).children(".not_installed").attr("data-name");var $btn=$(".install_"+name+":visible");var disabled=$btn.attr("disabled");if($btn.length){$btn.effect("highlight",1e3)}else{var color=$(this).css("color");$(this).closest("tr").find(".requires").attr("data-color",$(this).css("color")).css("color",color).effect("highlight",1e3)}return false});$("button.ProcessModuleSettings").click(function(){var $a=$(this).parents("tr").find(".ConfigurableModule").parent("a");window.location.href=$a.attr("href")+"&collapse_info=1"});if($("#modules_form").length>0){$("#modules_form").WireTabs({items:$(".Inputfields li.WireTab"),rememberTabs:true})}$("select.modules_section_select").change(function(){var section=$(this).val();var $sections=$(this).parent("p").siblings(".modules_section");if(section==""){$sections.show()}else{$sections.hide();$sections.filter(".modules_"+section).show()}document.cookie=$(this).attr("name")+"="+section;return true}).change();$(document).on("click","#head_button a",function(){document.cookie="WireTabs=tab_new_modules";return true});$("#Inputfield_new_seconds").change(function(){$("#submit_check").removeAttr("hidden").click();$(this).closest("form").submit()});$("#wrap_upload_module").removeClass("InputfieldItemList")});

View File

@@ -11,7 +11,7 @@
* This version also lifts several pieces of code from Soma's Modules Manager * This version also lifts several pieces of code from Soma's Modules Manager
* specific to the parts involved with downloading modules from the directory. * specific to the parts involved with downloading modules from the directory.
* *
* ProcessWire 3.x, Copyright 2019 by Ryan Cramer * ProcessWire 3.x, Copyright 2020 by Ryan Cramer
* https://processwire.com * https://processwire.com
* *
* @todo add support for module configuration inputfields with useLanguages option * @todo add support for module configuration inputfields with useLanguages option
@@ -32,7 +32,7 @@ class ProcessModule extends Process {
return array( return array(
'title' => __('Modules', __FILE__), // getModuleInfo title 'title' => __('Modules', __FILE__), // getModuleInfo title
'summary' => __('List, edit or install/uninstall modules', __FILE__), // getModuleInfo summary 'summary' => __('List, edit or install/uninstall modules', __FILE__), // getModuleInfo summary
'version' => 118, 'version' => 119,
'permanent' => true, 'permanent' => true,
'permission' => 'module-admin', 'permission' => 'module-admin',
'useNavJSON' => true, 'useNavJSON' => true,
@@ -121,6 +121,16 @@ class ProcessModule extends Process {
*/ */
protected $numFound = 0; protected $numFound = 0;
/**
* @var ProcessModuleInstall|null
*
*/
protected $installer = null;
/**
* Construct
*
*/
public function __construct() { public function __construct() {
$this->labels['download'] = $this->_('Download'); $this->labels['download'] = $this->_('Download');
if($this->input->get('update')) { if($this->input->get('update')) {
@@ -132,6 +142,7 @@ class ProcessModule extends Process {
$this->labels['module_information'] = $this->_x("Module Information", 'edit'); $this->labels['module_information'] = $this->_x("Module Information", 'edit');
$this->labels['download_now'] = $this->_('Download Now'); $this->labels['download_now'] = $this->_('Download Now');
$this->labels['download_dir'] = $this->_('Add Module From Directory'); $this->labels['download_dir'] = $this->_('Add Module From Directory');
$this->labels['add_manually'] = $this->_('Add Module Manually');
$this->labels['upload'] = $this->_('Upload'); $this->labels['upload'] = $this->_('Upload');
$this->labels['upload_zip'] = $this->_('Add Module From Upload'); $this->labels['upload_zip'] = $this->_('Add Module From Upload');
$this->labels['download_zip'] = $this->_('Add Module From URL'); $this->labels['download_zip'] = $this->_('Add Module From URL');
@@ -156,6 +167,14 @@ class ProcessModule extends Process {
require(dirname(__FILE__) . '/ProcessModuleInstall.php'); require(dirname(__FILE__) . '/ProcessModuleInstall.php');
} }
/**
* @return ProcessModuleInstall
*
*/
public function installer() {
if($this->installer === null) $this->installer = $this->wire(new ProcessModuleInstall());
return $this->installer;
}
/** /**
* Format a module version number from 999 to 9.9.9 * Format a module version number from 999 to 9.9.9
@@ -516,10 +535,21 @@ class ProcessModule extends Process {
$select->required = true; $select->required = true;
$select->attr('value', $newSeconds); $select->attr('value', $newSeconds);
/** @var InputfieldSubmit $btn */
$btn = $this->modules->get('InputfieldSubmit');
$btn->attr('hidden', 'hidden');
$btn->attr('name', 'submit_check');
$btn->textFormat = Inputfield::textFormatNone;
$btn->icon = 'check';
$btn->value = ' ';
$btn->setSmall(true);
$btn->setSecondary(true);
$btn = "<button type='submit' id='submit_check' name='submit_check' value='1' hidden>&nbsp;</button>";
/** @var InputfieldMarkup $markup */ /** @var InputfieldMarkup $markup */
$markup = $this->modules->get('InputfieldMarkup'); $markup = $this->modules->get('InputfieldMarkup');
$markup->icon = 'lightbulb-o'; $markup->icon = 'lightbulb-o';
$markup->value = $select->render() . $this->renderListTable($newModulesArray, false, false, true, true); $markup->value = $select->render() . ' ' . $btn . $this->renderListTable($newModulesArray, false, false, true, true);
$markup->label = $this->_('Recently Found and Installed Modules'); $markup->label = $this->_('Recently Found and Installed Modules');
$tab->add($markup); $tab->add($markup);
@@ -527,88 +557,128 @@ class ProcessModule extends Process {
$fieldset = $this->modules->get('InputfieldFieldset'); $fieldset = $this->modules->get('InputfieldFieldset');
$fieldset->label = $this->labels['download_dir']; $fieldset->label = $this->labels['download_dir'];
$fieldset->icon = 'cloud-download'; $fieldset->icon = 'cloud-download';
//if($this->wire('input')->post('new_seconds')) $fieldset->collapsed = Inputfield::collapsedYes;
/** @var InputfieldName $f */
$f = $this->modules->get('InputfieldName');
$f->attr('id+name', 'download_name');
$f->label = $this->_('Module Class Name');
$f->description =
$this->_('You may browse the modules directory and locate the module you want to download and install.') . ' ' .
sprintf(
$this->_('Type or paste in the class name for the module you want to install, then click the “%s” button to proceed.'),
$this->labels['get_module_info']
);
$f->notes = $this->_('The modules directory is located at [modules.processwire.com](http://modules.processwire.com)');
$f->attr('placeholder', $this->_('ModuleClassName')); // placeholder
$f->required = false;
$fieldset->add($f);
/** @var InputfieldSubmit $f */
$f = $this->modules->get('InputfieldSubmit');
$f->attr('id+name', 'download');
$f->value = $this->labels['get_module_info'];
$f->icon = $fieldset->icon;
$fieldset->add($f);
$tab->add($fieldset); $tab->add($fieldset);
//if($this->wire('input')->post('new_seconds')) $fieldset->collapsed = Inputfield::collapsedYes;
if($this->installer()->canInstallFromDirectory(false)) {
/** @var InputfieldName $f */
$f = $this->modules->get('InputfieldName');
$f->attr('id+name', 'download_name');
$f->label = $this->_('Module Class Name');
$f->description =
$this->_('You may browse the modules directory and locate the module you want to download and install.') . ' ' .
sprintf(
$this->_('Type or paste in the class name for the module you want to install, then click the “%s” button to proceed.'),
$this->labels['get_module_info']
);
$f->notes = sprintf($this->_('The modules directory is located at %s'), '[modules.processwire.com](https://modules.processwire.com)');
$f->attr('placeholder', $this->_('ModuleClassName')); // placeholder
$f->required = false;
$fieldset->add($f);
/** @var InputfieldSubmit $f */
$f = $this->modules->get('InputfieldSubmit');
$f->attr('id+name', 'download');
$f->value = $this->labels['get_module_info'];
$f->icon = $fieldset->icon;
$fieldset->add($f);
} else {
$fieldset->description = $this->installer()->installDisabledLabel('directory');
$fieldset->collapsed = Inputfield::collapsedYes;
}
/** @var InputfieldFieldset $fieldset */ /** @var InputfieldFieldset $fieldset */
$fieldset = $this->modules->get('InputfieldFieldset'); $fieldset = $this->modules->get('InputfieldFieldset');
$fieldset->label = $this->labels['download_zip']; $fieldset->label = $this->labels['download_zip'];
$fieldset->icon = 'download'; $fieldset->icon = 'download';
$fieldset->collapsed = Inputfield::collapsedYes; $fieldset->collapsed = Inputfield::collapsedYes;
$tab->add($fieldset);
$trustNote = $this->_('Be absolutely certain that you trust the source of the ZIP file.'); $trustNote = $this->_('Be absolutely certain that you trust the source of the ZIP file.');
/** @var InputfieldURL $f */ if($this->installer()->canInstallFromDownloadUrl(false)) {
$f = $this->modules->get('InputfieldURL'); /** @var InputfieldURL $f */
$f->attr('id+name', 'download_zip_url'); $f = $this->modules->get('InputfieldURL');
$f->label = $this->_('Module ZIP file URL'); $f->attr('id+name', 'download_zip_url');
$f->description = $this->_('Download a ZIP file containing a module. If you download a module that is already installed, the installed version will be overwritten with the newly downloaded version.'); $f->label = $this->_('Module ZIP file URL');
$f->notes = $trustNote; $f->description = $this->_('Download a ZIP file containing a module. If you download a module that is already installed, the installed version will be overwritten with the newly downloaded version.');
$f->attr('placeholder', $this->_('http://domain.com/ModuleName.zip')); // placeholder $f->notes = $trustNote;
$f->required = false; $f->attr('placeholder', $this->_('http://domain.com/ModuleName.zip')); // placeholder
$fieldset->add($f); $f->required = false;
$fieldset->add($f);
/** @var InputfieldSubmit $f */ /** @var InputfieldSubmit $f */
$f = $this->modules->get('InputfieldSubmit'); $f = $this->modules->get('InputfieldSubmit');
$f->attr('id+name', 'download_zip'); $f->attr('id+name', 'download_zip');
$f->value = $this->labels['download']; $f->value = $this->labels['download'];
$f->icon = $fieldset->icon; $f->icon = $fieldset->icon;
$fieldset->add($f); $fieldset->add($f);
$tab->add($fieldset); } else {
$fieldset->description = $this->installer()->installDisabledLabel('download');
}
/** @var InputfieldFieldset $fieldset */ /** @var InputfieldFieldset $fieldset */
$fieldset = $this->modules->get('InputfieldFieldset'); $fieldset = $this->modules->get('InputfieldFieldset');
$fieldset->label = $this->labels['upload_zip']; $fieldset->label = $this->labels['upload_zip'];
$fieldset->icon = 'upload'; $fieldset->icon = 'upload';
$fieldset->collapsed = Inputfield::collapsedYes; $fieldset->collapsed = Inputfield::collapsedYes;
/** @var InputfieldFile $f */
$f = $this->modules->get('InputfieldFile');
$f->extensions = 'zip';
$f->maxFiles = 1;
$f->descriptionRows = 0;
$f->overwrite = true;
$f->attr('id+name', 'upload_module');
$f->label = $this->_('Module ZIP File');
$f->description = $this->_('Upload a ZIP file containing module file(s). If you upload a module that is already installed, it will be overwritten with the one you upload.');
$f->notes = $trustNote;
$f->required = false;
$f->noCustomButton = true;
$fieldset->add($f);
$f = $this->modules->get('InputfieldSubmit');
$f->attr('id+name', 'upload');
$f->value = $this->labels['upload'];
$f->icon = $fieldset->icon;
$fieldset->add($f);
$tab->add($fieldset); $tab->add($fieldset);
if($this->installer()->canInstallFromFileUpload(false)) {
/** @var InputfieldFile $f */
$f = $this->modules->get('InputfieldFile');
$f->extensions = 'zip';
$f->maxFiles = 1;
$f->descriptionRows = 0;
$f->overwrite = true;
$f->attr('id+name', 'upload_module');
$f->label = $this->_('Module ZIP File');
$f->description = $this->_('Upload a ZIP file containing module file(s). If you upload a module that is already installed, it will be overwritten with the one you upload.');
$f->notes = $trustNote;
$f->required = false;
$f->noCustomButton = true;
$fieldset->add($f);
$f = $this->modules->get('InputfieldSubmit');
$f->attr('id+name', 'upload');
$f->value = $this->labels['upload'];
$f->icon = $fieldset->icon;
$fieldset->add($f);
} else {
$fieldset->description = $this->installer()->installDisabledLabel('upload');
}
/** @var InputfieldFieldset $fieldset */ /** @var InputfieldFieldset $fieldset */
$fieldset = $this->modules->get('InputfieldFieldset'); $fieldset = $this->modules->get('InputfieldFieldset');
$fieldset->attr('id', 'fieldset_check_new'); $fieldset->attr('id', 'fieldset_check_new');
$fieldset->label = $this->labels['add_manually'];
$fieldset->icon = 'plug';
$fieldset->collapsed = Inputfield::collapsedYes;
$tab->add($fieldset);
/** @var InputfieldMarkup $markup */
$markup = $this->modules->get('InputfieldMarkup');
$fieldset->add($markup);
$moduleNameLabel = $this->_('ModuleName'); // Example module class/directory name
$moduleNameDir = $this->wire()->config->urls->siteModules . $moduleNameLabel . '/';
$instructions = array(
sprintf($this->_('1. Copy a modules files into a new directory %s on the server.'), "<u>$moduleNameDir</u>") . ' * ',
sprintf($this->_('2. Click the “%s” button below, which will find the new module.'), $this->labels['reset']),
sprintf($this->_('3. Locate and click the “%s” button next to the new module.'), $this->labels['install_btn'])
);
$markup->value = '<p>' . implode('</p><p>', $instructions) . '</p>';
$markup->notes = '* ' . sprintf(
$this->_('Replace “%s” with the actual module name, which is typically its PHP class name.'),
$moduleNameLabel
);
/** @var InputfieldFieldset $fieldset */
/*
$fieldset = $this->modules->get('InputfieldFieldset');
$fieldset->attr('id', 'fieldset_check_new');
$fieldset->label = $this->labels['reset']; $fieldset->label = $this->labels['reset'];
$fieldset->description = $this->_('If you have placed new modules in /site/modules/ yourself, click this button to find them.'); $fieldset->description = $this->_('If you have placed new modules in /site/modules/ yourself, click this button to find them.');
$fieldset->collapsed = Inputfield::collapsedYes; $fieldset->collapsed = Inputfield::collapsedYes;
$fieldset->icon = 'refresh'; $fieldset->icon = 'refresh';
*/
/** @var InputfieldButton $submit */ /** @var InputfieldButton $submit */
$submit = $this->modules->get('InputfieldButton'); $submit = $this->modules->get('InputfieldButton');
@@ -617,7 +687,7 @@ class ProcessModule extends Process {
$submit->showInHeader(); $submit->showInHeader();
$submit->attr('name', 'reset'); $submit->attr('name', 'reset');
$submit->attr('value', $this->labels['reset']); $submit->attr('value', $this->labels['reset']);
$submit->icon = $fieldset->icon; $submit->icon = 'refresh';
$fieldset->add($submit); $fieldset->add($submit);
$tab->add($fieldset); $tab->add($fieldset);
@@ -1010,6 +1080,11 @@ class ProcessModule extends Process {
$warnings[] = $this->_('This module has no download URL specified and must be installed manually.'); $warnings[] = $this->_('This module has no download URL specified and must be installed manually.');
} }
if(!$this->installer()->canInstallFromDirectory(false)) {
$installable = false;
$markup->notes = trim($markup->notes . ' ' . $this->installer()->installDisabledLabel('directory'));
}
foreach($warnings as $warning) { foreach($warnings as $warning) {
$table->row(array($this->_x('Please Note', 'install-table'), "<strong class='ui-state-error-text'> $warning</strong>")); $table->row(array($this->_x('Please Note', 'install-table'), "<strong class='ui-state-error-text'> $warning</strong>"));
} }
@@ -1073,9 +1148,8 @@ class ProcessModule extends Process {
if(!$className) throw new WireException("No class name specified"); if(!$className) throw new WireException("No class name specified");
$destinationDir = $this->wire('config')->paths->siteModules . $className . '/'; $destinationDir = $this->wire('config')->paths->siteModules . $className . '/';
$install = $this->wire(new ProcessModuleInstall());
$completedDir = $install->downloadModule($url, $destinationDir); $completedDir = $this->installer()->downloadModule($url, $destinationDir);
if($completedDir) { if($completedDir) {
return $this->buildDownloadSuccessForm($className)->render(); return $this->buildDownloadSuccessForm($className)->render();
} else { } else {
@@ -1158,15 +1232,13 @@ class ProcessModule extends Process {
public function ___executeUpload($inputName = '') { public function ___executeUpload($inputName = '') {
if(!$inputName) throw new WireException("This URL may not be accessed directly"); if(!$inputName) throw new WireException("This URL may not be accessed directly");
$install = $this->wire(new ProcessModuleInstall()); $this->installer()->uploadModule($inputName);
$install->uploadModule($inputName);
$this->session->redirect('./?reset=1'); $this->session->redirect('./?reset=1');
} }
public function ___executeDownloadURL($url = '') { public function ___executeDownloadURL($url = '') {
if(!$url) throw new WireException("This URL may not be accessed directly"); if(!$url) throw new WireException("This URL may not be accessed directly");
$install = $this->wire(new ProcessModuleInstall()); $this->installer()->downloadModuleFromUrl($url);
$install->downloadModule($url);
$this->session->redirect('./?reset=1'); $this->session->redirect('./?reset=1');
} }

View File

@@ -1,10 +1,13 @@
<?php namespace ProcessWire; <?php namespace ProcessWire;
/** /**
* Class ProcessModuleInstall * Installation helper for ProcessModule
* *
* Provides methods for internative module installation for ProcessModule * Provides methods for internative module installation for ProcessModule
* *
* ProcessWire 3.x, Copyright 2020 by Ryan Cramer
* https://processwire.com
*
*/ */
class ProcessModuleInstall extends Wire { class ProcessModuleInstall extends Wire {
@@ -29,16 +32,30 @@ class ProcessModuleInstall extends Wire {
* This primarily checks that needed dirs are writable and ZipArchive is available. * This primarily checks that needed dirs are writable and ZipArchive is available.
* *
* @param bool $notify Specify true to make it queue the relevant reason/error message if upload/download not supported. (default=false) * @param bool $notify Specify true to make it queue the relevant reason/error message if upload/download not supported. (default=false)
* @param string $type One of 'upload' or 'download' or omit for general check
* @return bool * @return bool
* *
*/ */
public function canUploadDownload($notify = true) { public function canUploadDownload($notify = true, $type = '') {
$config = $this->wire()->config;
if($type) {
$a = $config->moduleInstall;
$allow = is_array($a) && isset($a[$type]) ? $a[$type] : false;
if($allow === 'debug' && !$config->debug) $allow = false;
if(!$allow) {
if($notify) $this->error(
sprintf($this->_('Module install option “%s”'), $type) . ' - ' .
$this->installDisabledLabel($type)
);
return false;
}
}
$can = true; $can = true;
if(!is_writable($this->config->paths->cache)) { if(!is_writable($config->paths->cache)) {
if($notify) $this->error($this->_('Make sure /site/assets/cache/ directory is writeable for PHP.')); if($notify) $this->error($this->_('Make sure /site/assets/cache/ directory is writeable for PHP.'));
$can = false; $can = false;
} }
if(!is_writable($this->config->paths->siteModules)) { if(!is_writable($config->paths->siteModules)) {
if($notify) $this->error($this->_('Make sure your site modules directory (/site/modules/) is writeable for PHP.')); if($notify) $this->error($this->_('Make sure your site modules directory (/site/modules/) is writeable for PHP.'));
$can = false; $can = false;
} }
@@ -50,6 +67,40 @@ class ProcessModuleInstall extends Wire {
return $can; return $can;
} }
/**
* Module upload allowed?
*
* @param bool $notify
* @return bool
*
*
*/
public function canInstallFromFileUpload($notify = true) {
return $this->canUploadDownload($notify, 'upload');
}
/**
* Module download from URL allowed?
*
* @param bool $notify
* @return bool
*
*/
public function canInstallFromDownloadUrl($notify = true) {
return $this->canUploadDownload($notify, 'download');
}
/**
* Module install/upgrade from directory allowed?
*
* @param bool $notify
* @return bool
*
*/
public function canInstallFromDirectory($notify = true) {
return $this->canUploadDownload($notify, 'directory');
}
/** /**
* Find all module files, recursively in Path * Find all module files, recursively in Path
* *
@@ -347,7 +398,7 @@ class ProcessModuleInstall extends Wire {
*/ */
public function uploadModule($inputName = 'upload_module', $destinationDir = '') { public function uploadModule($inputName = 'upload_module', $destinationDir = '') {
if(!$this->canUploadDownload()) { if(!$this->canInstallFromFileUpload()) {
$this->error($this->_('Unable to complete upload')); $this->error($this->_('Unable to complete upload'));
return false; return false;
} }
@@ -381,16 +432,18 @@ class ProcessModuleInstall extends Wire {
/** /**
* Given a URL to a ZIP file, download it, unzip it, and move to /site/modules/[ModuleName] * Given a URL to a ZIP file, download it, unzip it, and move to /site/modules/[ModuleName]
* *
* @param $url * @param string $url Download URL
* @param string $destinationDir Optional destination path for files (omit to auto-determine) * @param string $destinationDir Optional destination path for files (omit to auto-determine)
* @param string $type Specify type of 'download' or 'directory'
* @return bool|string Returns destinationDir on success, false on failure. * @return bool|string Returns destinationDir on success, false on failure.
* *
*/ */
public function downloadModule($url, $destinationDir = '') { public function downloadModule($url, $destinationDir = '', $type = 'download') {
if(!$this->canUploadDownload()) { if($type === 'directory') {
$this->error($this->_('Unable to complete download')); if(!$this->canInstallFromDirectory()) return false;
return false; } else {
if(!$this->canInstallFromDownloadUrl()) return false;
} }
if(!preg_match('{^https?://}i', $url)) { if(!preg_match('{^https?://}i', $url)) {
@@ -425,6 +478,60 @@ class ProcessModuleInstall extends Wire {
return $success ? $destinationDir : false; return $success ? $destinationDir : false;
} }
/**
* Download module from URL
*
* @param string $url
* @param string $destinationDir
* @return bool|string
* @since 3.0.162
*
*/
public function downloadModuleFromUrl($url, $destinationDir = '') {
return $this->downloadModule($url, $destinationDir, 'download');
}
/**
* Download module from directory
*
* @param string $url
* @param string $destinationDir
* @return bool|string
* @since 3.0.162
*
*/
public function downloadModuleFromDirectory($url, $destinationDir = '') {
return $this->downloadModule($url, $destinationDir, 'directory');
}
/**
* Return label to indicate option is disabled and how to enable it
*
* @param string $type
* @return string
* @since 3.0.162
*
*/
public function installDisabledLabel($type) {
$config = $this->wire()->config;
$a = $config->moduleInstall;
$debug = !empty($a[$type]) && $a[$type] === 'debug';
$opt1 = "`\$config->moduleInstall('$type', true);` " . $this->_('to enable always');
$opt2 = "`\$config->debug = true;` " . $this->_('temporarily');
$opt3 = "`\$config->moduleInstall('$type', 'debug');` " . $this->_('to enable in debug mode only');
$file = $config->urls->site . 'config.php';
$inst = $this->_('To enable, edit file %1$s and specify: %2$s …or… %3$s');
if($debug) {
return
$this->_('This install option is configured to be available only in debug mode.') . ' ' .
sprintf($inst, "$file", "\n$opt2", "\n$opt1");
} else {
return
$this->_('This install option is currently disabled.') . ' ' .
sprintf($inst, "$file", "\n$opt1", "\n$opt3");
}
}
} }