From 6481f6db337d8e20378565340d72082c13e38108 Mon Sep 17 00:00:00 2001 From: Dries Buytaert Date: Thu, 8 Oct 2009 15:40:34 +0000 Subject: =?UTF-8?q?-=20Patch=20#456088=20by=20dww,=20JohnAlbin=20|=20Dave?= =?UTF-8?q?=20Reid,=20G=C3=A1bor=20Hojtsy,=20pwolanin,=20tic2000,=20meba:?= =?UTF-8?q?=20sub-themes=20not=20notified=20of=20security=20updates=20for?= =?UTF-8?q?=20base=20themes.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../update/tests/update_test_basetheme.1_1-sec.xml | 52 ++++++++++++ modules/update/tests/update_test_subtheme.1_0.xml | 34 ++++++++ modules/update/update.compare.inc | 44 +++++++++- modules/update/update.module | 3 + modules/update/update.report.inc | 86 ++++++++++++++----- modules/update/update.test | 99 ++++++++++++++++++++++ 6 files changed, 296 insertions(+), 22 deletions(-) create mode 100644 modules/update/tests/update_test_basetheme.1_1-sec.xml create mode 100644 modules/update/tests/update_test_subtheme.1_0.xml (limited to 'modules') diff --git a/modules/update/tests/update_test_basetheme.1_1-sec.xml b/modules/update/tests/update_test_basetheme.1_1-sec.xml new file mode 100644 index 000000000..5c11c0316 --- /dev/null +++ b/modules/update/tests/update_test_basetheme.1_1-sec.xml @@ -0,0 +1,52 @@ + + +Update test base theme +update_test_basetheme +Drupal +7.x +1 +1 +1 +published +http://example.com/project/update_test_basetheme + + ProjectsThemes + + + + update_test_basetheme 7.x-1.1 + 7.x-1.1 + DRUPAL-7--1-1 + 1 + 1 + published + http://example.com/update_test_basetheme-7-x-1-1-release + http://example.com/update_test_basetheme-7.x-1.1.tar.gz + 1250624521 + b966255555d9c9b86d480ca08cfaa98e + 1073763241 + + Release typeSecurity update + Release typeNew features + Release typeBug fixes + + + + update_test_basetheme 7.x-1.0 + 7.x-1.0 + DRUPAL-7--1-0 + 1 + 0 + published + http://example.com/update_test_basetheme-7-x-1-0-release + http://example.com/update_test_basetheme-7.x-1.0.tar.gz + 1250524521 + b966255555d9c9b86d480ca08cfaa98e + 1073741824 + + Release typeNew features + Release typeBug fixes + + + + diff --git a/modules/update/tests/update_test_subtheme.1_0.xml b/modules/update/tests/update_test_subtheme.1_0.xml new file mode 100644 index 000000000..5d04ec8bd --- /dev/null +++ b/modules/update/tests/update_test_subtheme.1_0.xml @@ -0,0 +1,34 @@ + + +Update test subtheme +update_test_subtheme +Drupal +7.x +1 +1 +1 +published +http://example.com/project/update_test_subtheme + + ProjectsThemes + + + + update_test_subtheme 7.x-1.0 + 7.x-1.0 + DRUPAL-7--1-0 + 1 + 0 + published + http://example.com/update_test_subtheme-7-x-1-0-release + http://example.com/update_test_subtheme-7.x-1.0.tar.gz + 1250524521 + b966255555d9c9b86d480ca08cfaa98e + 1073741824 + + Release typeNew features + Release typeBug fixes + + + + diff --git a/modules/update/update.compare.inc b/modules/update/update.compare.inc index e5f4caee7..db216d7cf 100644 --- a/modules/update/update.compare.inc +++ b/modules/update/update.compare.inc @@ -81,7 +81,24 @@ function update_get_projects() { */ function _update_process_info_list(&$projects, $list, $project_type, $status) { foreach ($list as $file) { - if ($file->status != $status) { + // A disabled base theme of an enabled sub-theme still has all of its code + // run by the sub-theme, so we include it in our "enabled" projects list. + if ($status && !$file->status && !empty($file->sub_themes)) { + foreach ($file->sub_themes as $key => $name) { + // Build a list of enabled sub-themes. + if ($list[$key]->status) { + $file->enabled_sub_themes[$key] = $name; + } + } + // If there are no enabled subthemes, we should ignore this base theme + // for the enabled case. If the site is trying to display disabled + // themes, we'll catch it then. + if (empty($file->enabled_sub_themes)) { + continue; + } + } + // Otherwise, just add projects of the proper status to our list. + elseif ($file->status != $status) { continue; } @@ -133,10 +150,25 @@ function _update_process_info_list(&$projects, $list, $project_type, $status) { else { $project_display_type = $project_type; } - if (empty($status)) { + if (empty($status) && empty($file->enabled_sub_themes)) { // If we're processing disabled modules or themes, append a suffix. + // However, we don't do this to a a base theme with enabled + // subthemes, since we treat that case as if it is enabled. $project_display_type .= '-disabled'; } + // Add a list of sub-themes that "depend on" the project and a list of base + // themes that are "required by" the project. + if ($project_name == 'drupal') { + // Drupal core is always required, so this extra info would be noise. + $sub_themes = array(); + $base_themes = array(); + } + else { + // Add list of enabled sub-themes. + $sub_themes = !empty($file->enabled_sub_themes) ? $file->enabled_sub_themes : array(); + // Add list of base themes. + $base_themes = !empty($file->base_themes) ? $file->base_themes : array(); + } if (!isset($projects[$project_name])) { // Only process this if we haven't done this project, since a single // project can have multiple modules or themes. @@ -147,6 +179,8 @@ function _update_process_info_list(&$projects, $list, $project_type, $status) { 'includes' => array($file->name => $file->info['name']), 'project_type' => $project_display_type, 'project_status' => $status, + 'sub_themes' => $sub_themes, + 'base_themes' => $base_themes, ); } elseif ($projects[$project_name]['project_type'] == $project_display_type) { @@ -158,6 +192,12 @@ function _update_process_info_list(&$projects, $list, $project_type, $status) { $projects[$project_name]['includes'][$file->name] = $file->info['name']; $projects[$project_name]['info']['_info_file_ctime'] = max($projects[$project_name]['info']['_info_file_ctime'], $file->info['_info_file_ctime']); $projects[$project_name]['datestamp'] = max($projects[$project_name]['datestamp'], $file->info['datestamp']); + if (!empty($sub_themes)) { + $projects[$project_name]['sub_themes'] += $sub_themes; + } + if (!empty($base_themes)) { + $projects[$project_name]['base_themes'] += $base_themes; + } } elseif (empty($status)) { // If we have a project_name that matches, but the project_display_type diff --git a/modules/update/update.module b/modules/update/update.module index 80849031a..1de6e028c 100644 --- a/modules/update/update.module +++ b/modules/update/update.module @@ -172,6 +172,9 @@ function update_theme() { 'update_version' => array( 'arguments' => array('version' => NULL, 'tag' => NULL, 'class' => array()), ), + 'update_status_label' => array( + 'arguments' => array('status' => NULL), + ), ); } diff --git a/modules/update/update.report.inc b/modules/update/update.report.inc index 831b5d217..4d9b8f785 100644 --- a/modules/update/update.report.inc +++ b/modules/update/update.report.inc @@ -41,6 +41,15 @@ function theme_update_report($data) { $notification_level = variable_get('update_notification_threshold', 'all'); + // Create an array of status values keyed by module or theme name, since + // we'll need this while generating the report if we have to cross reference + // anything (e.g. subthemes which have base themes missing an update). + foreach ($data as $project) { + foreach ($project['includes'] as $key => $name) { + $status[$key] = $project['status']; + } + } + foreach ($data as $project) { switch ($project['status']) { case UPDATE_CURRENT: @@ -67,26 +76,8 @@ function theme_update_report($data) { } $row = '
'; - switch ($project['status']) { - case UPDATE_NOT_SECURE: - $row .= '' . t('Security update required!') . ''; - break; - case UPDATE_REVOKED: - $row .= '' . t('Revoked!') . ''; - break; - case UPDATE_NOT_SUPPORTED: - $row .= '' . t('Not supported!') . ''; - break; - case UPDATE_NOT_CURRENT: - $row .= '' . t('Update available') . ''; - break; - case UPDATE_CURRENT: - $row .= '' . t('Up to date') . ''; - break; - default: - $row .= check_plain($project['reason']); - break; - } + $status_label = theme('update_status_label', $project['status']); + $row .= !empty($status_label) ? $status_label : check_plain($project['reason']); $row .= '' . $icon . ''; $row .= "
\n"; @@ -194,6 +185,33 @@ function theme_update_report($data) { } $row .= "\n"; + if (!empty($project['base_themes'])) { + $row .= '
'; + asort($project['base_themes']); + $base_themes = array(); + foreach ($project['base_themes'] as $base_key => $base_theme) { + switch ($status[$base_key]) { + case UPDATE_NOT_SECURE: + case UPDATE_REVOKED: + case UPDATE_NOT_SUPPORTED: + $base_themes[] = t('%base_theme (!base_label)', array('%base_theme' => $base_theme, '!base_label' => theme('update_status_label', $status[$base_key]))); + break; + + default: + $base_themes[] = theme('placeholder', $base_theme); + } + } + $row .= t('Depends on: !basethemes', array('!basethemes' => implode(', ', $base_themes))); + $row .= "
\n"; + } + + if (!empty($project['sub_themes'])) { + $row .= '
'; + sort($project['sub_themes']); + $row .= t('Required by: %subthemes', array('%subthemes' => implode(', ', $project['sub_themes']))); + $row .= "
\n"; + } + $row .= "\n"; // info div. if (!isset($rows[$project['project_type']])) { @@ -224,6 +242,34 @@ function theme_update_report($data) { return $output; } +/** + * Generate the HTML for the label to display for a project's update status. + * + * @param $status + * The integer code for a project's current update status. + * + * @see update_calculate_project_data() + */ +function theme_update_status_label($status) { + switch ($status) { + case UPDATE_NOT_SECURE: + return '' . t('Security update required!') . ''; + + case UPDATE_REVOKED: + return '' . t('Revoked!') . ''; + + case UPDATE_NOT_SUPPORTED: + return '' . t('Not supported!') . ''; + + case UPDATE_NOT_CURRENT: + return '' . t('Update available') . ''; + + case UPDATE_CURRENT: + return '' . t('Up to date') . ''; + + } +} + /** * Theme the version display of a project. * diff --git a/modules/update/update.test b/modules/update/update.test index 58e9b6982..a274e3864 100644 --- a/modules/update/update.test +++ b/modules/update/update.test @@ -266,5 +266,104 @@ class UpdateTestContribCase extends UpdateTestHelper { $this->assertTrue(strpos($this->drupalGetContent(), $bbb_project_link) < strpos($this->drupalGetContent(), $ccc_project_link), "'BBB Update test' project is listed before the 'CCC Update test' project"); } + /** + * Test that subthemes are notified about security updates for base themes. + */ + function testUpdateBaseThemeSecurityUpdate() { + // Only enable the subtheme, not the base theme. + db_update('system') + ->fields(array('status' => 1)) + ->condition('type', 'theme') + ->condition('name', 'update_test_subtheme') + ->execute(); + + // Define the initial state for core and the subtheme. + $system_info = array( + // We want core to be version 7.0. + '#all' => array( + 'version' => '7.0', + ), + // Show the update_test_basetheme + 'update_test_basetheme' => array( + 'project' => 'update_test_basetheme', + 'version' => '7.x-1.0', + 'hidden' => FALSE, + ), + // Show the update_test_subtheme + 'update_test_subtheme' => array( + 'project' => 'update_test_subtheme', + 'version' => '7.x-1.0', + 'hidden' => FALSE, + ), + ); + variable_set('update_test_system_info', $system_info); + $xml_mapping = array( + 'drupal' => '0', + 'update_test_subtheme' => '1_0', + 'update_test_basetheme' => '1_1-sec', + ); + $this->refreshUpdateStatus($xml_mapping); + $this->drupalGet('admin/reports/updates'); + $this->assertText(t('Security update required!')); + $this->assertRaw(l(t('Update test base theme'), 'http://example.com/project/update_test_basetheme'), t('Link to the Update test base theme project appears.')); + } + + /** + * Test that disabled themes are only shown when desired. + */ + function testUpdateShowDisabledThemes() { + // Make sure all the update_test_* themes are disabled. + db_update('system') + ->fields(array('status' => 0)) + ->condition('type', 'theme') + ->condition('name', 'update_test_%', 'LIKE') + ->execute(); + + // Define the initial state for core and the test contrib themes. + $system_info = array( + // We want core to be version 7.0. + '#all' => array( + 'version' => '7.0', + ), + // The update_test_basetheme should be visible and up to date. + 'update_test_basetheme' => array( + 'project' => 'update_test_basetheme', + 'version' => '7.x-1.1', + 'hidden' => FALSE, + ), + // The update_test_subtheme should be visible and up to date. + 'update_test_subtheme' => array( + 'project' => 'update_test_subtheme', + 'version' => '7.x-1.0', + 'hidden' => FALSE, + ), + ); + variable_set('update_test_system_info', $system_info); + $xml_mapping = array( + 'drupal' => '0', + 'update_test_subtheme' => '1_0', + 'update_test_basetheme' => '1_1-sec', + ); + $base_theme_project_link = l(t('Update test base theme'), 'http://example.com/project/update_test_basetheme'); + $sub_theme_project_link = l(t('Update test subtheme'), 'http://example.com/project/update_test_subtheme'); + foreach (array(TRUE, FALSE) as $check_disabled) { + variable_set('update_check_disabled', $check_disabled); + $this->refreshUpdateStatus($xml_mapping); + $this->drupalGet('admin/reports/updates'); + // In neither case should we see the "Themes" heading for enabled themes. + $this->assertNoText(t('Themes')); + if ($check_disabled) { + $this->assertText(t('Disabled themes')); + $this->assertRaw($base_theme_project_link, t('Link to the Update test base theme project appears.')); + $this->assertRaw($sub_theme_project_link, t('Link to the Update test subtheme project appears.')); + } + else { + $this->assertNoText(t('Disabled themes')); + $this->assertNoRaw($base_theme_project_link, t('Link to the Update test base theme project does not appear.')); + $this->assertNoRaw($sub_theme_project_link, t('Link to the Update test subtheme project does not appear.')); + } + } + } + } -- cgit v1.2.3