Skip to content

Commit

Permalink
MDL-20438 initial support for checking available core update
Browse files Browse the repository at this point in the history
In case of Moodle code itself, there is no plugin_manager like class
available so the checker class itself must be aware of versions and
actually do the checks. On the other hand, we can always rely that
version, release and maturity are always returned by the remote server.
  • Loading branch information
mudrd8mz committed Mar 30, 2012
1 parent e761138 commit 55585f3
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 59 deletions.
15 changes: 14 additions & 1 deletion admin/index.php
Expand Up @@ -55,13 +55,15 @@
require('../config.php');
require_once($CFG->libdir.'/adminlib.php'); // various admin-only functions
require_once($CFG->libdir.'/upgradelib.php'); // general upgrade/install related functions
require_once($CFG->libdir.'/pluginlib.php'); // available updates notifications

$id = optional_param('id', '', PARAM_TEXT);
$confirmupgrade = optional_param('confirmupgrade', 0, PARAM_BOOL);
$confirmrelease = optional_param('confirmrelease', 0, PARAM_BOOL);
$confirmplugins = optional_param('confirmplugincheck', 0, PARAM_BOOL);
$showallplugins = optional_param('showallplugins', 0, PARAM_BOOL);
$agreelicense = optional_param('agreelicense', 0, PARAM_BOOL);
$fetchupdates = optional_param('fetchupdates', 0, PARAM_BOOL);

// Check some PHP server settings

Expand Down Expand Up @@ -369,7 +371,18 @@
$dbproblems = $DB->diagnose();
$maintenancemode = !empty($CFG->maintenance_enabled);

$updateschecker = available_update_checker::instance();
$availableupdates = $updateschecker->get_core_update_info(MATURITY_STABLE); // todo make it configurable
$availableupdatesfetch = $updateschecker->get_last_timefetched();

admin_externalpage_setup('adminnotifications');

if ($fetchupdates) {
require_sesskey();
$updateschecker->fetch();
redirect($PAGE->url);
}

$output = $PAGE->get_renderer('core', 'admin');
echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
$cronoverdue, $dbproblems, $maintenancemode);
$cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch);
80 changes: 79 additions & 1 deletion admin/renderer.php
Expand Up @@ -202,14 +202,18 @@ public function upgrade_plugin_check_page(plugin_manager $pluginman, $version, $
* @param bool $cronoverdue warn cron not running
* @param bool $dbproblems warn db has problems
* @param bool $maintenancemode warn in maintenance mode
* @param array|null $availableupdates array of available_update_info objects or null
* @param int|null $availableupdatesfetch timestamp of the most recent updates fetch or null (unknown)
*
* @return string HTML to output.
*/
public function admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
$cronoverdue, $dbproblems, $maintenancemode) {
$cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch) {
$output = '';

$output .= $this->header();
$output .= $this->maturity_info($maturity);
$output .= $this->available_updates($availableupdates, $availableupdatesfetch);
$output .= $this->insecure_dataroot_warning($insecuredataroot);
$output .= $this->display_errors_warning($errorsdisplayed);
$output .= $this->cron_overdue_warning($cronoverdue);
Expand Down Expand Up @@ -400,6 +404,80 @@ protected function maturity_info($maturity) {
'generalbox adminwarning maturityinfo maturity'.$maturity);
}

/**
* Displays the info about available Moodle updates
*
* @param array|null $updates array of available_update_info objects or null
* @param int|null $fetch timestamp of the most recent updates fetch or null (unknown)
* @return string
*/
protected function available_updates($updates, $fetch) {

$updateinfo = $this->box_start('generalbox adminwarning availableupdatesinfo');
if (is_array($updates)) {
$updateinfo .= $this->heading(get_string('updateavailable', 'core_admin'), 3);
foreach ($updates as $update) {
$updateinfo .= $this->moodle_available_update_info($update);
}
} else {
$updateinfo .= $this->heading(get_string('updateavailablenot', 'core_admin'), 3);
}

$updateinfo .= $this->container_start('checkforupdates');
$updateinfo .= $this->single_button(new moodle_url($this->page->url, array('fetchupdates' => 1)), get_string('checkforupdates', 'core_plugin'));
if ($fetch) {
$updateinfo .= $this->container(get_string('checkforupdateslast', 'core_plugin',
userdate($fetch, get_string('strftimedatetime', 'core_langconfig'))));
}
$updateinfo .= $this->container_end();

$updateinfo .= $this->box_end();

return $updateinfo;
}

/**
* Helper method to render the information about the available Moodle update
*
* @param available_update_info $updateinfo information about the available Moodle core update
*/
protected function moodle_available_update_info(available_update_info $updateinfo) {

$boxclasses = 'moodleupdateinfo';
$info = array();

if (isset($updateinfo->release)) {
$info[] = html_writer::tag('span', get_string('updateavailable_release', 'core_admin', $updateinfo->release),
array('class' => 'info release'));
}

if (isset($updateinfo->version)) {
$info[] = html_writer::tag('span', get_string('updateavailable_version', 'core_admin', $updateinfo->version),
array('class' => 'info version'));
}

if (isset($updateinfo->maturity)) {
$info[] = html_writer::tag('span', get_string('maturity'.$updateinfo->maturity, 'core_admin'),
array('class' => 'info maturity'));
$boxclasses .= ' maturity'.$updateinfo->maturity;
}

if (isset($updateinfo->download)) {
$info[] = html_writer::link($updateinfo->download, get_string('download'), array('class' => 'info download'));
}

if (isset($updateinfo->url)) {
$info[] = html_writer::link($updateinfo->url, get_string('updateavailable_moreinfo', 'core_plugin'),
array('class' => 'info more'));
}

$box = $this->output->box_start($boxclasses);
$box .= $this->output->box(implode(html_writer::tag('span', ' ', array('class' => 'separator')), $info), '');
$box .= $this->output->box_end();

return $box;
}

/**
* Display a link to the release notes.
* @return string HTML to output.
Expand Down
5 changes: 5 additions & 0 deletions lang/en/admin.php
Expand Up @@ -968,6 +968,11 @@
$string['unsuspenduser'] = 'Activate user account';
$string['updateaccounts'] = 'Update existing accounts';
$string['updatecomponent'] = 'Update component';
$string['updateavailable'] = 'There is a newer Moodle version available!';
$string['updateavailable_moreinfo'] = 'More info...';
$string['updateavailable_release'] = 'Moodle {$a}';
$string['updateavailable_version'] = 'Version {$a}';
$string['updateavailablenot'] = 'Your Moodle code seems to be up-to-date';
$string['upgradestart'] = 'Upgrade';
$string['upgradeerror'] = 'Unknown error upgrading {$a->plugin} to version {$a->version}, can not continue.';
$string['upgradeforumread'] = 'A new feature has been added in Moodle 1.5 to track read/unread forum posts.<br />To use this functionality you need to <a href="{$a}">update your tables</a>.';
Expand Down
141 changes: 86 additions & 55 deletions lib/pluginlib.php
Expand Up @@ -64,11 +64,8 @@ class plugin_manager {

/**
* Direct initiation not allowed, use the factory method {@link self::instance()}
*
* @todo we might want to specify just a single plugin type to work with
*/
protected function __construct() {
$this->get_plugins(true);
}

/**
Expand Down Expand Up @@ -576,6 +573,12 @@ class available_update_checker {
protected $recentfetch = null;
/** @var null|array the recent response from the update notification provider */
protected $recentresponse = null;
/** @var null|string the numerical version of the local Moodle code */
protected $currentversion = null;
/** @var null|string branch of the local Moodle code */
protected $currentbranch = null;
/** @var array of (string)frankestyle => (string)version list of additional plugins deployed at this site */
protected $currentplugins = array();

/**
* Direct initiation not allowed, use the factory method {@link self::instance()}
Expand All @@ -601,52 +604,6 @@ public static function instance() {
return self::$singletoninstance;
}

/**
* Sets the local version
*
* If the version is set before the request is done, the version info will
* be sent to the remote site as a part of the request. The returned data can
* be filtered so that they contain just information relevant to the sent
* version.
*
* @param string $version our local Moodle version, usually $CFG->version
*/
public function set_local_version($version) {
$this->localversion = $version;
}

/**
* Sets the local release info
*
* If the release is set before the request is done, the release info will
* be sent to the remote site as a part of the request. The returned data can
* be filtered so that they contain just information relevant to the sent
* release/build.
*
* @param string $version our local Moodle version, usually $CFG->release
*/
public function set_local_release($release) {
$this->localrelease = $release;
}

/**
* Sets the list of plugins and their version at the local Moodle site
*
* The keys of the passed array are frankenstyle component names of plugins. The
* values are the on-disk versions of these plugins (allowing the null value where
* the version can't be obtained for any reason).
* If the plugins are set before the request is done, their list will be sent
* to the remote site as a part of the request. The returned data can
* be filtered so that they contain just information about the installed plugins.
* To obtain a list of all available plugins, do not set this list prior to calling
* {@link self::fetch()}
*
* @param array $plugins of (string)component => (string)version
*/
public function set_local_plugins(array $plugins) {
$this->localplugins = $plugins;
}

/**
* Returns the timestamp of the last execution of {@link fetch()}
*
Expand Down Expand Up @@ -675,6 +632,40 @@ public function fetch() {
$this->store_response($response);
}

/**
* Returns the available update information for Moodle core
*
* The returned structure is an array of available_update_info objects or null
* if there no such info available.
*
* @param int $minmaturity minimal maturity level to return, returns all by default
* @return null|stdClass null or array of available_update_info objects
*/
public function get_core_update_info($minmaturity = 0) {

$this->load_current_environment();

$updates = $this->get_update_info('core');
if (empty($updates)) {
return null;
}
$return = array();
foreach ($updates as $update) {
if (isset($update->maturity) and ($update->maturity < $minmaturity)) {
continue;
}
if ($update->version > $this->currentversion) {
$return[] = $update;
}
}

if (empty($return)) {
return null;
}

return $return;
}

/**
* Returns the available update information for the given component
*
Expand All @@ -684,7 +675,7 @@ public function fetch() {
* 'version'. Other possible properties are 'release', 'maturity', 'url' and 'downloadurl'.
*
* @param string $component frankenstyle
* @return null|stdClass null or array of objects
* @return null|stdClass null or array of available_update_info objects
*/
public function get_update_info($component) {

Expand Down Expand Up @@ -818,6 +809,34 @@ protected function prepare_request_url() {
}
}

/**
* Sets the properties currentversion, currentbranch and currentplugins
*
* @param bool $forcereload
*/
protected function load_current_environment($forcereload=false) {
global $CFG;

if (!is_null($this->currentversion) and !$forcereload) {
// nothing to do
return;
}

require($CFG->dirroot.'/version.php');
$this->currentversion = $version;

$this->currentbranch = moodle_major_version(true);

$pluginman = plugin_manager::instance();
foreach ($pluginman->get_plugins() as $type => $plugins) {
foreach ($plugins as $plugin) {
if (!$plugin->is_standard()) {
$this->currentplugins[$plugin->component] = $plugin->versiondisk;
}
}
}
}

/**
* Returns the list of HTTP params to be sent to the updates provider URL
*
Expand All @@ -826,6 +845,7 @@ protected function prepare_request_url() {
protected function prepare_request_params() {
global $CFG;

$this->load_current_environment();
$this->restore_response();

$params = array();
Expand All @@ -835,15 +855,26 @@ protected function prepare_request_params() {
$params['ticket'] = $this->recentresponse['ticket'];
}

if (isset($this->localversion)) {
$params['version'] = $this->localversion;
if (isset($this->currentversion)) {
$params['version'] = $this->currentversion;
} else {
throw new coding_exception('Main Moodle version must be already known here');
}

if (isset($this->localrelease)) {
$params['release'] = $this->localrelease;
if (isset($this->currentbranch)) {
$params['branch'] = $this->currentbranch;
} else {
throw new coding_exception('Moodle release must be already known here');
}

$plugins = array();
foreach ($this->currentplugins as $plugin => $version) {
$plugins[] = $plugin.'@'.$version;
}
if (!empty($plugins)) {
$params['plugins'] = implode(',', $plugins);
}

// todo localplugins
return $params;
}
}
Expand Down
25 changes: 23 additions & 2 deletions lib/simpletest/testpluginlib.php
Expand Up @@ -139,6 +139,15 @@ protected function restore_response($forcereload = false) {
$this->recentresponse = $this->decode_response($this->get_fake_response());
}

protected function load_current_environment($forcereload=false) {
}

public function fake_current_environment($version, $branch, array $plugins) {
$this->currentversion = $version;
$this->currentbranch = $branch;
$this->currentplugins = $plugins;
}

private function get_fake_response() {
$fakeresponse = array(
'status' => 'OK',
Expand All @@ -159,8 +168,8 @@ private function get_fake_response() {
),
array(
'version' => 2012120100.00,
'release' => '2.4 (Build: 20121201)',
'maturity' => 200,
'release' => '2.4dev (Build: 20121201)',
'maturity' => 50,
'url' => 'http://download.moodle.org/',
'download' => 'http://download.moodle.org/download.php/MOODLE_24_STABLE/moodle-2.4.0-latest.zip',
),
Expand Down Expand Up @@ -234,5 +243,17 @@ class available_update_checker_test extends UnitTestCase {
public function test_core_available_update() {
$provider = testable_available_update_checker::instance();
$this->assertTrue($provider instanceof available_update_checker);

$provider->fake_current_environment(2012060102.00, '2.3', array());
$updates = $provider->get_core_update_info();
$this->assertEqual(count($updates), 2);

$provider->fake_current_environment(2012060103.00, '2.3', array());
$updates = $provider->get_core_update_info();
$this->assertEqual(count($updates), 1);

$provider->fake_current_environment(2012060103.00, '2.3', array());
$updates = $provider->get_core_update_info(MATURITY_STABLE);
$this->assertNull($updates);
}
}

0 comments on commit 55585f3

Please sign in to comment.