Skip to content

Commit

Permalink
MDL-49329 admin: Add ability to cancel installation of a new plugin
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mudrd8mz committed Oct 8, 2015
1 parent f2d8ed4 commit 2f29cf6
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 55 deletions.
57 changes: 45 additions & 12 deletions admin/index.php
Expand Up @@ -106,6 +106,9 @@
$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');
Expand Down Expand Up @@ -272,6 +275,12 @@

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.
Expand Down Expand Up @@ -327,27 +336,39 @@
die();

} else if (empty($confirmplugins)) {
// No sesskey support guaranteed here, because sessions might not work yet.

$strplugincheck = get_string('plugincheck');

$PAGE->navbar->add($strplugincheck);
$PAGE->set_title($strplugincheck);
$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)) {
Expand All @@ -358,16 +379,14 @@
}

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);
Expand All @@ -391,19 +410,34 @@

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);
$PAGE->set_title($strplugincheck);
$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();
Expand All @@ -429,7 +463,7 @@
}

// 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)));
Expand All @@ -438,11 +472,10 @@

// 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);
Expand Down
65 changes: 52 additions & 13 deletions admin/renderer.php
Expand Up @@ -206,11 +206,15 @@ public function upgrade_plugin_check_page(core_plugin_manager $pluginman, \core\
$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'))));
Expand Down Expand Up @@ -877,7 +881,13 @@ public function plugins_check_table(core_plugin_manager $pluginman, $version, ar
);
$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) {

Expand Down Expand Up @@ -954,6 +964,18 @@ public function plugins_check_table(core_plugin_manager $pluginman, $version, ar
}
$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) {
Expand Down Expand Up @@ -1014,19 +1036,36 @@ public function plugins_check_table(core_plugin_manager $pluginman, $version, ar
$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']) {
Expand Down Expand Up @@ -1104,7 +1143,7 @@ protected function missing_dependencies(core_plugin_manager $pluginman) {

// 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')
);
Expand Down
2 changes: 2 additions & 0 deletions lang/en/plugin.php
Expand Up @@ -27,6 +27,8 @@

$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}"';
Expand Down
37 changes: 37 additions & 0 deletions lib/classes/plugin_manager.php
Expand Up @@ -1531,6 +1531,43 @@ public static function standard_plugins_list($type) {
}
}

/**
* 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
*
Expand Down

0 comments on commit 2f29cf6

Please sign in to comment.