MDL-49329 admin: Add ability to cancel installation of a new plugin
The plugins check screen now provides buttons to cancel installation of a plugin. Available only for new installations (not upgrades) and for additional plugins (not standard), given that the web server process has write access to the plugin folder. This has also been reported as MDL-48535. As a part of the patch, there is improved processing of page URLs during the upgrade. All this dancing around $reload URL is not needed once the $PAGE->url is properly set to guide the admin on the correct page during the upgrade process.
This commit is contained in:
+45
-12
@@ -106,6 +106,9 @@ $agreelicense = optional_param('agreelicense', 0, PARAM_BOOL);
|
||||
$fetchupdates = optional_param('fetchupdates', 0, PARAM_BOOL);
|
||||
$newaddonreq = optional_param('installaddonrequest', null, PARAM_RAW);
|
||||
$upgradekeyhash = optional_param('upgradekeyhash', null, PARAM_ALPHANUM);
|
||||
$installalldeps = optional_param('installalldeps', false, PARAM_BOOL);
|
||||
$abortinstall = optional_param('abortinstall', null, PARAM_COMPONENT);
|
||||
$abortinstallx = optional_param('abortinstallx', null, PARAM_BOOL);
|
||||
|
||||
// Set up PAGE.
|
||||
$url = new moodle_url('/admin/index.php');
|
||||
@@ -272,6 +275,12 @@ if ($CFG->version != $DB->get_field('config', 'value', array('name'=>'version'))
|
||||
|
||||
if (!$cache and $version > $CFG->version) { // upgrade
|
||||
|
||||
$PAGE->set_url(new moodle_url($PAGE->url, array(
|
||||
'confirmupgrade' => $confirmupgrade,
|
||||
'confirmrelease' => $confirmrelease,
|
||||
'confirmplugincheck' => $confirmplugins,
|
||||
)));
|
||||
|
||||
check_upgrade_key($upgradekeyhash);
|
||||
|
||||
// Warning about upgrading a test site.
|
||||
@@ -327,6 +336,8 @@ if (!$cache and $version > $CFG->version) { // upgrade
|
||||
die();
|
||||
|
||||
} else if (empty($confirmplugins)) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
|
||||
$strplugincheck = get_string('plugincheck');
|
||||
|
||||
$PAGE->navbar->add($strplugincheck);
|
||||
@@ -334,20 +345,30 @@ if (!$cache and $version > $CFG->version) { // upgrade
|
||||
$PAGE->set_heading($strplugincheck);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
$reloadurl = new moodle_url($PAGE->url, array('confirmupgrade' => 1, 'confirmrelease' => 1, 'cache' => 0));
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
|
||||
if ($abortinstallx) {
|
||||
$pluginman->cancel_all_plugin_installations();
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
if ($abortinstall) {
|
||||
$pluginman->cancel_plugin_installation($abortinstall);
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
|
||||
if ($fetchupdates) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$updateschecker = \core\update\checker::instance();
|
||||
if ($updateschecker->enabled()) {
|
||||
$updateschecker->fetch();
|
||||
}
|
||||
redirect($reloadurl);
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
$deployer = \core\update\deployer::instance();
|
||||
if ($deployer->enabled()) {
|
||||
$deployer->initialize($reloadurl, $reloadurl);
|
||||
$deployer->initialize($PAGE->url, $PAGE->url);
|
||||
|
||||
$deploydata = $deployer->submitted_data();
|
||||
if (!empty($deploydata)) {
|
||||
@@ -358,16 +379,14 @@ if (!$cache and $version > $CFG->version) { // upgrade
|
||||
}
|
||||
|
||||
echo $output->upgrade_plugin_check_page(core_plugin_manager::instance(), \core\update\checker::instance(),
|
||||
$version, $showallplugins, $reloadurl, new moodle_url($PAGE->url, array(
|
||||
'confirmupgrade' => 1, 'confirmrelease' => 1, 'confirmplugincheck' => 1, 'cache' => 0)));
|
||||
$version, $showallplugins, $PAGE->url, new moodle_url($PAGE->url, array('confirmplugincheck' => 1)));
|
||||
die();
|
||||
|
||||
} else {
|
||||
// Always verify plugin dependencies!
|
||||
$failed = array();
|
||||
if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
|
||||
$reloadurl = new moodle_url($PAGE->url, array('confirmupgrade' => 1, 'confirmrelease' => 1, 'cache' => 0));
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, $reloadurl);
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, $PAGE->url);
|
||||
die();
|
||||
}
|
||||
unset($failed);
|
||||
@@ -391,12 +410,15 @@ if (!$cache and $branch <> $CFG->branch) { // Update the branch
|
||||
|
||||
if (!$cache and moodle_needs_upgrading()) {
|
||||
|
||||
$PAGE->set_url(new moodle_url($PAGE->url, array('confirmplugincheck' => $confirmplugins)));
|
||||
|
||||
check_upgrade_key($upgradekeyhash);
|
||||
|
||||
if (!$PAGE->headerprinted) {
|
||||
// means core upgrade or installation was not already done
|
||||
|
||||
if (!$confirmplugins) {
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
$strplugincheck = get_string('plugincheck');
|
||||
|
||||
$PAGE->navbar->add($strplugincheck);
|
||||
@@ -404,6 +426,18 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
$PAGE->set_heading($strplugincheck);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
if ($abortinstallx) {
|
||||
require_sesskey();
|
||||
$pluginman->cancel_all_plugin_installations();
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
if ($abortinstall) {
|
||||
require_sesskey();
|
||||
$pluginman->cancel_plugin_installation($abortinstall);
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
if ($fetchupdates) {
|
||||
require_sesskey();
|
||||
$updateschecker = \core\update\checker::instance();
|
||||
@@ -429,7 +463,7 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
}
|
||||
|
||||
// Show plugins info.
|
||||
echo $output->upgrade_plugin_check_page(core_plugin_manager::instance(), \core\update\checker::instance(),
|
||||
echo $output->upgrade_plugin_check_page($pluginman, \core\update\checker::instance(),
|
||||
$version, $showallplugins,
|
||||
new moodle_url($PAGE->url),
|
||||
new moodle_url($PAGE->url, array('confirmplugincheck' => 1, 'cache' => 0)));
|
||||
@@ -438,11 +472,10 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
|
||||
// Make sure plugin dependencies are always checked.
|
||||
$failed = array();
|
||||
if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
|
||||
if (!$pluginman->all_plugins_ok($version, $failed)) {
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
$reloadurl = new moodle_url($PAGE->url, array('cache' => 0));
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, $reloadurl);
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, $PAGE->url);
|
||||
die();
|
||||
}
|
||||
unset($failed);
|
||||
|
||||
+52
-13
@@ -206,11 +206,15 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$output = '';
|
||||
|
||||
$output .= $this->header();
|
||||
$output .= $this->box_start('generalbox');
|
||||
$output .= html_writer::tag('p', get_string('pluginchecknotice', 'core_plugin'));
|
||||
$output .= $this->box_start('generalbox', 'plugins-check-page');
|
||||
$output .= html_writer::tag('p', get_string('pluginchecknotice', 'core_plugin'), array('class' => 'page-description'));
|
||||
|
||||
if ($checker->enabled()) {
|
||||
$output .= $this->container_start('checkforupdates');
|
||||
$output .= $this->single_button(new moodle_url($reloadurl, array('fetchupdates' => 1)), get_string('checkforupdates', 'core_plugin'));
|
||||
$output .= $this->single_button(
|
||||
new moodle_url($reloadurl, array('fetchupdates' => 1)),
|
||||
get_string('checkforupdates', 'core_plugin')
|
||||
);
|
||||
if ($timefetched = $checker->get_last_timefetched()) {
|
||||
$output .= $this->container(get_string('checkforupdateslast', 'core_plugin',
|
||||
userdate($timefetched, get_string('strftimedatetime', 'core_langconfig'))));
|
||||
@@ -877,7 +881,13 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
);
|
||||
$table->data = array();
|
||||
|
||||
$numofhighlighted = array(); // number of highlighted rows per this subsection
|
||||
// Number of displayed plugins per type (we call them 'highlighted'
|
||||
// because in early version of the page, we always displayed all the
|
||||
// plugins rows and highlighted were those requiring attention.
|
||||
$numofhighlighted = array();
|
||||
|
||||
// List of all components we can cancel installation of.
|
||||
$installabortable = array();
|
||||
|
||||
foreach ($plugininfo as $type => $plugins) {
|
||||
|
||||
@@ -954,6 +964,18 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
}
|
||||
$status = html_writer::span(get_string('status_' . $statuscode, 'core_plugin'), $statusclass);
|
||||
|
||||
if ($statuscode == core_plugin_manager::PLUGIN_STATUS_NEW and !$plugin->is_standard()) {
|
||||
if ($pluginman->is_plugin_folder_removable($plugin->component)) {
|
||||
$installabortable[] = $plugin->component;
|
||||
$status .= $this->output->single_button(
|
||||
new moodle_url($this->page->url, array('abortinstall' => $plugin->component)),
|
||||
get_string('cancelinstallone', 'core_plugin'),
|
||||
'post',
|
||||
array('class' => 'actionbutton')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$availableupdates = $plugin->available_updates();
|
||||
if (!empty($availableupdates)) {
|
||||
foreach ($availableupdates as $availableupdate) {
|
||||
@@ -1014,19 +1036,36 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$out .= $this->output->container_end();
|
||||
|
||||
} else {
|
||||
$out = $this->output->container_start('somehighlighted', 'plugins-check-info');
|
||||
$out = $this->output->container_start('somehighlighted', 'plugins-check-info');
|
||||
|
||||
if (empty($options['full'])) {
|
||||
$out .= $this->output->heading(get_string('somehighlighted', 'core_plugin', $sumofhighlighted));
|
||||
$out .= html_writer::link(new moodle_url($this->page->url,
|
||||
array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 1, 'cache' => 0)),
|
||||
get_string('somehighlightedinfo', 'core_plugin'));
|
||||
} else {
|
||||
$out .= $this->output->heading(get_string('somehighlightedall', 'core_plugin', $sumofhighlighted));
|
||||
$out .= html_writer::link(new moodle_url($this->page->url,
|
||||
array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 0, 'cache' => 0)),
|
||||
get_string('somehighlightedonly', 'core_plugin'));
|
||||
}
|
||||
$out .= $this->output->container_end();
|
||||
|
||||
$out .= $this->output->container_start('actions');
|
||||
|
||||
if ($installabortable) {
|
||||
$out .= $this->output->single_button(
|
||||
new moodle_url($this->page->url, array('abortinstallx' => 1)),
|
||||
get_string('cancelinstallall', 'core_plugin', count($installabortable)),
|
||||
'post',
|
||||
array('class' => 'actionbutton')
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($options['full'])) {
|
||||
$out .= html_writer::link(new moodle_url($this->page->url, array('confirmupgrade' => 1, 'confirmrelease' => 1,
|
||||
'cache' => 0, 'showallplugins' => 1)), get_string('somehighlightedinfo', 'core_plugin'));
|
||||
} else {
|
||||
$out .= html_writer::link(
|
||||
new moodle_url($this->page->url, array('confirmupgrade' => 1, 'confirmrelease' => 1,
|
||||
'cache' => 0, 'showallplugins' => 0)), get_string('somehighlightedonly', 'core_plugin'));
|
||||
}
|
||||
|
||||
$out .= $this->output->container_end(); // .actions
|
||||
$out .= $this->output->container_end(); // #plugins-check-info .somehighlighted
|
||||
}
|
||||
|
||||
if ($sumofhighlighted > 0 or $options['full']) {
|
||||
@@ -1104,7 +1143,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
// TODO implement the button functionality.
|
||||
$out .= html_writer::link(
|
||||
new moodle_url('/admin/tool/installaddon/'),
|
||||
new moodle_url($this->page->url, array('installalldeps' => 1, 'sesskey' => sesskey())),
|
||||
get_string('dependencyinstallmissing', 'core_plugin'),
|
||||
array('class' => 'btn')
|
||||
);
|
||||
|
||||
@@ -27,6 +27,8 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['actions'] = 'Actions';
|
||||
$string['availability'] = 'Availability';
|
||||
$string['cancelinstallall'] = 'Cancel new installations ({$a})';
|
||||
$string['cancelinstallone'] = 'Cancel installation';
|
||||
$string['checkforupdates'] = 'Check for available updates';
|
||||
$string['checkforupdateslast'] = 'Last check done on {$a}';
|
||||
$string['detectedmisplacedplugin'] = 'Plugin "{$a->component}" is installed in incorrect location "{$a->current}", expected location is "{$a->expected}"';
|
||||
|
||||
@@ -1531,6 +1531,43 @@ class core_plugin_manager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the plugin code directory if it is not installed yet.
|
||||
*
|
||||
* This is intended for the plugins check screen to give the admin a chance
|
||||
* to cancel the installation of just unzipped plugin before the database
|
||||
* upgrade happens.
|
||||
*
|
||||
* @param string $component
|
||||
* @return bool
|
||||
*/
|
||||
public function cancel_plugin_installation($component) {
|
||||
|
||||
$plugin = $this->get_plugin_info($component);
|
||||
|
||||
if (empty($plugin) or $plugin->is_standard() or $plugin->get_status() !== self::PLUGIN_STATUS_NEW
|
||||
or !$this->is_plugin_folder_removable($plugin->component)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return remove_dir($plugin->rootdir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels installation of all new additional plugins.
|
||||
*/
|
||||
public function cancel_all_plugin_installations() {
|
||||
|
||||
foreach ($this->get_plugins() as $type => $plugins) {
|
||||
foreach ($plugins as $plugin) {
|
||||
if (!$plugin->is_standard() and $plugin->get_status() === self::PLUGIN_STATUS_NEW
|
||||
and $this->is_plugin_folder_removable($plugin->component)) {
|
||||
$this->cancel_plugin_installation($plugin->component);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorders plugin types into a sequence to be displayed
|
||||
*
|
||||
|
||||
@@ -532,7 +532,7 @@ img.iconsmall {
|
||||
text-align: right
|
||||
}
|
||||
|
||||
// Plugins check.
|
||||
// Plugins overview control panel.
|
||||
#page-admin-index #notice .checkforupdates {
|
||||
text-align: center;
|
||||
}
|
||||
@@ -583,37 +583,86 @@ img.iconsmall {
|
||||
background-color: @inputDisabledBackground;
|
||||
}
|
||||
|
||||
#plugins-check .requires-ok {
|
||||
.muted
|
||||
}
|
||||
// Plugins check page displayed during upgrade.
|
||||
#plugins-check-page {
|
||||
|
||||
#plugins-check .displayname {
|
||||
.pluginicon {
|
||||
margin-right: 5px;
|
||||
width: 16px;
|
||||
}
|
||||
.plugindir {
|
||||
.muted;
|
||||
font-size: @fontSizeSmall;
|
||||
}
|
||||
}
|
||||
|
||||
#plugins-check .requires ul {
|
||||
margin-left: 13px; // To undo the default 25px, does not look that great inside a table cell;
|
||||
}
|
||||
|
||||
#plugins-check .status .pluginupdateinfo {
|
||||
padding: 5px 10px;
|
||||
margin: 10px 0px;
|
||||
background-color: @infoBackground;
|
||||
.border-radius(10px);
|
||||
}
|
||||
|
||||
#plugins-check-available-dependencies {
|
||||
.displayname .component {
|
||||
font-size: @fontSizeSmall;
|
||||
.page-description {
|
||||
.muted
|
||||
}
|
||||
|
||||
// Check for updates.
|
||||
.checkforupdates {
|
||||
.singlebutton {
|
||||
margin: 5px 0;
|
||||
padding: 0;
|
||||
input {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Section before the plugins check table.
|
||||
#plugins-check-info {
|
||||
.actions {
|
||||
.actionbutton {
|
||||
display: inline-block;
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
input {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Plugins check table.
|
||||
#plugins-check {
|
||||
.requires-ok {
|
||||
.muted
|
||||
}
|
||||
|
||||
.displayname {
|
||||
.pluginicon {
|
||||
margin-right: 5px;
|
||||
width: 16px;
|
||||
}
|
||||
.plugindir {
|
||||
.muted;
|
||||
font-size: @fontSizeSmall;
|
||||
}
|
||||
}
|
||||
|
||||
.requires ul {
|
||||
margin-left: 13px; // To undo the default 25px, does not look that great inside a table cell;
|
||||
}
|
||||
|
||||
.status {
|
||||
.actionbutton {
|
||||
margin: 5px 0px;
|
||||
padding: 0;
|
||||
input {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.pluginupdateinfo {
|
||||
padding: 5px 10px;
|
||||
margin: 10px 0px;
|
||||
background-color: @infoBackground;
|
||||
.border-radius(10px);
|
||||
.separator:after {
|
||||
content: " | ";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Available dependencies on the plugins check page.
|
||||
#plugins-check-available-dependencies {
|
||||
.displayname .component {
|
||||
font-size: @fontSizeSmall;
|
||||
.muted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#page-admin-index .upgradepluginsinfo {
|
||||
@@ -645,10 +694,6 @@ img.iconsmall {
|
||||
border-left: 1px dotted @grayLight;
|
||||
}
|
||||
|
||||
#plugins-check .status .pluginupdateinfo .separator:after {
|
||||
content: " | ";
|
||||
}
|
||||
|
||||
#plugins-control-panel .msg td {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user