Example #1
0
 /**
  * Returns a page about the update status of projects.
  *
  * @return array
  *   A build array with the update status of projects.
  */
 public function updateStatus()
 {
     $build = array('#theme' => 'update_report');
     if ($available = update_get_available(TRUE)) {
         $this->moduleHandler()->loadInclude('update', 'compare.inc');
         $build['#data'] = update_calculate_project_data($available);
     }
     return $build;
 }
Example #2
0
 /**
  * Obtains release info for all installed projects via update.module.
  *
  * @see update_get_available().
  * @see update_manual_status().
  */
 protected function getAvailableReleases()
 {
     // We force a refresh if the cache is not available.
     if (!cache_get('update_available_releases', 'cache_update')) {
         $this->refresh();
     }
     $available = update_get_available(TRUE);
     // Force to invalidate some update_status caches that are only cleared
     // when visiting update status report page.
     if (function_exists('_update_cache_clear')) {
         _update_cache_clear('update_project_data');
         _update_cache_clear('update_project_projects');
     }
     return $available;
 }
Example #3
0
 /**
  * Tests when there is no available release data for a contrib module.
  */
 function testNoReleasesAvailable()
 {
     $system_info = array('#all' => array('version' => '8.0.0'), 'aaa_update_test' => array('project' => 'aaa_update_test', 'version' => '8.x-1.0', 'hidden' => FALSE));
     $this->config('update_test.settings')->set('system_info', $system_info)->save();
     $this->refreshUpdateStatus(array('drupal' => '0.0', 'aaa_update_test' => 'no-releases'));
     $this->drupalGet('admin/reports/updates');
     // Cannot use $this->standardTests() because we need to check for the
     // 'No available releases found' string.
     $this->assertRaw('<h3>' . t('Drupal core') . '</h3>');
     $this->assertRaw(\Drupal::l(t('Drupal'), Url::fromUri('http://example.com/project/drupal')));
     $this->assertText(t('Up to date'));
     $this->assertRaw('<h3>' . t('Modules') . '</h3>');
     $this->assertNoText(t('Update available'));
     $this->assertText(t('No available releases found'));
     $this->assertNoRaw(\Drupal::l(t('AAA Update test'), Url::fromUri('http://example.com/project/aaa_update_test')));
     $available = update_get_available();
     $this->assertFalse(isset($available['aaa_update_test']['fetch_status']), 'Results are cached even if no releases are available.');
 }
 /**
  * Tests upload, extraction, and update of a module.
  */
 public function testUploadModule()
 {
     // Ensure that the update information is correct before testing.
     update_get_available(TRUE);
     // Images are not valid archives, so get one and try to install it. We
     // need an extra variable to store the result of drupalGetTestFiles()
     // since reset() takes an argument by reference and passing in a constant
     // emits a notice in strict mode.
     $imageTestFiles = $this->drupalGetTestFiles('image');
     $invalidArchiveFile = reset($imageTestFiles);
     $edit = array('files[project_upload]' => $invalidArchiveFile->uri);
     // This also checks that the correct archive extensions are allowed.
     $this->drupalPostForm('admin/modules/install', $edit, t('Install'));
     $this->assertText(t('Only files with the following extensions are allowed: @archive_extensions.', array('@archive_extensions' => archiver_get_extensions())), 'Only valid archives can be uploaded.');
     $this->assertUrl('admin/modules/install');
     // Check to ensure an existing module can't be reinstalled. Also checks that
     // the archive was extracted since we can't know if the module is already
     // installed until after extraction.
     $validArchiveFile = __DIR__ . '/../../tests/aaa_update_test.tar.gz';
     $edit = array('files[project_upload]' => $validArchiveFile);
     $this->drupalPostForm('admin/modules/install', $edit, t('Install'));
     $this->assertText(t('@module_name is already installed.', array('@module_name' => 'AAA Update test')), 'Existing module was extracted and not reinstalled.');
     $this->assertUrl('admin/modules/install');
     // Ensure that a new module can be extracted and installed.
     $updaters = drupal_get_updaters();
     $moduleUpdater = $updaters['module']['class'];
     $installedInfoFilePath = $this->container->get('update.root') . '/' . $moduleUpdater::getRootDirectoryRelativePath() . '/update_test_new_module/update_test_new_module.info.yml';
     $this->assertFalse(file_exists($installedInfoFilePath), 'The new module does not exist in the filesystem before it is installed with the Update Manager.');
     $validArchiveFile = __DIR__ . '/../../tests/update_test_new_module/8.x-1.0/update_test_new_module.tar.gz';
     $edit = array('files[project_upload]' => $validArchiveFile);
     $this->drupalPostForm('admin/modules/install', $edit, t('Install'));
     // Check that submitting the form takes the user to authorize.php.
     $this->assertUrl('core/authorize.php');
     $this->assertTitle('Update manager | Drupal');
     // Check for a success message on the page, and check that the installed
     // module now exists in the expected place in the filesystem.
     $this->assertRaw(t('Installed %project_name successfully', array('%project_name' => 'update_test_new_module')));
     $this->assertTrue(file_exists($installedInfoFilePath), 'The new module exists in the filesystem after it is installed with the Update Manager.');
     // Ensure the links are relative to the site root and not
     // core/authorize.php.
     $this->assertLink(t('Install another module'));
     $this->assertLinkByHref(Url::fromRoute('update.module_install')->toString());
     $this->assertLink(t('Enable newly added modules'));
     $this->assertLinkByHref(Url::fromRoute('system.modules_list')->toString());
     $this->assertLink(t('Administration pages'));
     $this->assertLinkByHref(Url::fromRoute('system.admin')->toString());
     // Ensure we can reach the "Install another module" link.
     $this->clickLink(t('Install another module'));
     $this->assertResponse(200);
     $this->assertUrl('admin/modules/install');
     // Check that the module has the correct version before trying to update
     // it. Since the module is installed in sites/simpletest, which only the
     // child site has access to, standard module API functions won't find it
     // when called here. To get the version, the info file must be parsed
     // directly instead.
     $info_parser = new InfoParserDynamic();
     $info = $info_parser->parse($installedInfoFilePath);
     $this->assertEqual($info['version'], '8.x-1.0');
     // Enable the module.
     $this->drupalPostForm('admin/modules', array('modules[Testing][update_test_new_module][enable]' => TRUE), t('Install'));
     // Define the update XML such that the new module downloaded above needs an
     // update from 8.x-1.0 to 8.x-1.1.
     $update_test_config = $this->config('update_test.settings');
     $system_info = array('update_test_new_module' => array('project' => 'update_test_new_module'));
     $update_test_config->set('system_info', $system_info)->save();
     $xml_mapping = array('update_test_new_module' => '1_1');
     $this->refreshUpdateStatus($xml_mapping);
     // Run the updates for the new module.
     $this->drupalPostForm('admin/reports/updates/update', array('projects[update_test_new_module]' => TRUE), t('Download these updates'));
     $this->drupalPostForm(NULL, array('maintenance_mode' => FALSE), t('Continue'));
     $this->assertText(t('Update was completed successfully.'));
     $this->assertRaw(t('Installed %project_name successfully', array('%project_name' => 'update_test_new_module')));
     // Parse the info file again to check that the module has been updated to
     // 8.x-1.1.
     $info = $info_parser->parse($installedInfoFilePath);
     $this->assertEqual($info['version'], '8.x-1.1');
 }
 /**
  * {@inheritdoc}
  */
 public function buildForm(array $form, FormStateInterface $form_state)
 {
     $this->moduleHandler->loadInclude('update', 'inc', 'update.manager');
     $last_markup = array('#theme' => 'update_last_check', '#last' => $this->state->get('update.last_check') ?: 0);
     $form['last_check'] = array('#markup' => drupal_render($last_markup));
     if (!_update_manager_check_backends($form, 'update')) {
         return $form;
     }
     $available = update_get_available(TRUE);
     if (empty($available)) {
         $form['message'] = array('#markup' => $this->t('There was a problem getting update information. Try again later.'));
         return $form;
     }
     $form['#attached']['library'][] = 'update/drupal.update.admin';
     // This will be a nested array. The first key is the kind of project, which
     // can be either 'enabled', 'disabled', 'manual' (projects which require
     // manual updates, such as core). Then, each subarray is an array of
     // projects of that type, indexed by project short name, and containing an
     // array of data for cells in that project's row in the appropriate table.
     $projects = array();
     // This stores the actual download link we're going to update from for each
     // project in the form, regardless of if it's enabled or disabled.
     $form['project_downloads'] = array('#tree' => TRUE);
     $this->moduleHandler->loadInclude('update', 'inc', 'update.compare');
     $project_data = update_calculate_project_data($available);
     foreach ($project_data as $name => $project) {
         // Filter out projects which are up to date already.
         if ($project['status'] == UPDATE_CURRENT) {
             continue;
         }
         // The project name to display can vary based on the info we have.
         if (!empty($project['title'])) {
             if (!empty($project['link'])) {
                 $project_name = l($project['title'], $project['link']);
             } else {
                 $project_name = String::checkPlain($project['title']);
             }
         } elseif (!empty($project['info']['name'])) {
             $project_name = String::checkPlain($project['info']['name']);
         } else {
             $project_name = String::checkPlain($name);
         }
         if ($project['project_type'] == 'theme' || $project['project_type'] == 'theme-disabled') {
             $project_name .= ' ' . $this->t('(Theme)');
         }
         if (empty($project['recommended'])) {
             // If we don't know what to recommend they upgrade to, we should skip
             // the project entirely.
             continue;
         }
         $recommended_release = $project['releases'][$project['recommended']];
         $recommended_version = $recommended_release['version'] . ' ' . l($this->t('(Release notes)'), $recommended_release['release_link'], array('attributes' => array('title' => $this->t('Release notes for @project_title', array('@project_title' => $project['title'])))));
         if ($recommended_release['version_major'] != $project['existing_major']) {
             $recommended_version .= '<div title="Major upgrade warning" class="update-major-version-warning">' . $this->t('This update is a major version update which means that it may not be backwards compatible with your currently running version.  It is recommended that you read the release notes and proceed at your own risk.') . '</div>';
         }
         // Create an entry for this project.
         $entry = array('title' => $project_name, 'installed_version' => $project['existing_version'], 'recommended_version' => $recommended_version);
         switch ($project['status']) {
             case UPDATE_NOT_SECURE:
             case UPDATE_REVOKED:
                 $entry['title'] .= ' ' . $this->t('(Security update)');
                 $entry['#weight'] = -2;
                 $type = 'security';
                 break;
             case UPDATE_NOT_SUPPORTED:
                 $type = 'unsupported';
                 $entry['title'] .= ' ' . $this->t('(Unsupported)');
                 $entry['#weight'] = -1;
                 break;
             case UPDATE_UNKNOWN:
             case UPDATE_NOT_FETCHED:
             case UPDATE_NOT_CHECKED:
             case UPDATE_NOT_CURRENT:
                 $type = 'recommended';
                 break;
             default:
                 // Jump out of the switch and onto the next project in foreach.
                 continue 2;
         }
         // Use the project title for the tableselect checkboxes.
         $entry['title'] = array('data' => array('#title' => $entry['title'], '#markup' => $entry['title']));
         $entry['#attributes'] = array('class' => array('update-' . $type));
         // Drupal core needs to be upgraded manually.
         $needs_manual = $project['project_type'] == 'core';
         if ($needs_manual) {
             // There are no checkboxes in the 'Manual updates' table so it will be
             // rendered by _theme('table'), not _theme('tableselect'). Since the data
             // formats are incompatible, we convert now to the format expected by
             // _theme('table').
             unset($entry['#weight']);
             $attributes = $entry['#attributes'];
             unset($entry['#attributes']);
             $entry = array('data' => $entry) + $attributes;
         } else {
             $form['project_downloads'][$name] = array('#type' => 'value', '#value' => $recommended_release['download_link']);
         }
         // Based on what kind of project this is, save the entry into the
         // appropriate subarray.
         switch ($project['project_type']) {
             case 'core':
                 // Core needs manual updates at this time.
                 $projects['manual'][$name] = $entry;
                 break;
             case 'module':
             case 'theme':
                 $projects['enabled'][$name] = $entry;
                 break;
             case 'module-disabled':
             case 'theme-disabled':
                 $projects['disabled'][$name] = $entry;
                 break;
         }
     }
     if (empty($projects)) {
         $form['message'] = array('#markup' => $this->t('All of your projects are up to date.'));
         return $form;
     }
     $headers = array('title' => array('data' => $this->t('Name'), 'class' => array('update-project-name')), 'installed_version' => $this->t('Installed version'), 'recommended_version' => $this->t('Recommended version'));
     if (!empty($projects['enabled'])) {
         $form['projects'] = array('#type' => 'tableselect', '#header' => $headers, '#options' => $projects['enabled']);
         if (!empty($projects['disabled'])) {
             $form['projects']['#prefix'] = '<h2>' . $this->t('Enabled') . '</h2>';
         }
     }
     if (!empty($projects['disabled'])) {
         $form['disabled_projects'] = array('#type' => 'tableselect', '#header' => $headers, '#options' => $projects['disabled'], '#weight' => 1, '#prefix' => '<h2>' . $this->t('Disabled') . '</h2>');
     }
     // If either table has been printed yet, we need a submit button and to
     // validate the checkboxes.
     if (!empty($projects['enabled']) || !empty($projects['disabled'])) {
         $form['actions'] = array('#type' => 'actions');
         $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Download these updates'));
     }
     if (!empty($projects['manual'])) {
         $prefix = '<h2>' . $this->t('Manual updates required') . '</h2>';
         $prefix .= '<p>' . $this->t('Updates of Drupal core are not supported at this time.') . '</p>';
         $form['manual_updates'] = array('#type' => 'table', '#header' => $headers, '#rows' => $projects['manual'], '#prefix' => $prefix, '#weight' => 120);
     }
     return $form;
 }
Example #6
0
 /**
  * @return array
  *
  * @see _update_process_info_list()
  */
 public function getUpdates()
 {
     $available = update_get_available(true);
     if (!$available) {
         return array();
     }
     module_load_include('inc', 'update', 'update.compare');
     $updates = array();
     $data = update_calculate_project_data($available);
     foreach ($data as $slug => $update) {
         // Disabled modules have a type of 'module-disabled'.
         $type = explode('-', $update['project_type'], 2);
         $type = $type[0];
         if ($update['recommended'] === $update['existing_version'] || empty($update['recommended'])) {
             continue;
         }
         $updates[$slug] = array('slug' => $slug, 'name' => $update['title'], 'type' => $type, 'project' => $update['info']['project'], 'package' => $update['info']['package'], 'existingVersion' => $update['info']['version'], 'recommendedVersion' => $update['recommended'], 'recommendedDownloadLink' => $update['releases'][$update['recommended']]['download_link'], 'status' => self::$statusMap[$update['status']], 'includes' => empty($update['includes']) ? array() : array_keys($update['includes']), 'enabled' => (bool) $update['status'], 'baseThemes' => array_keys($update['base_themes']), 'subThemes' => array_keys($update['sub_themes']));
     }
     return $updates;
 }
 /**
  * [getUpdateRows description]
  * @return [type] [description]
  */
 public function getUpdateRows()
 {
     // Return
     $updates = array();
     // Get update information from cache and refreshes it when necessary.
     $available = update_get_available();
     // Pull Projects
     module_load_include('inc', 'update', 'update.compare');
     $project_data = update_calculate_project_data($available);
     // Process Rows
     foreach ($project_data as $name => $project) {
         // Filter out projects which are up to date already.
         if ($project['status'] == UPDATE_CURRENT) {
             continue;
         }
         // The project name to display can vary based on the info we have.
         if (!empty($project['title'])) {
             $project_name = check_plain($project['title']);
         } elseif (!empty($project['info']['name'])) {
             $project_name = check_plain($project['info']['name']);
         } else {
             $project_name = check_plain($name);
         }
         if ($project['project_type'] == 'theme' || $project['project_type'] == 'theme-disabled') {
             $project_name .= ' ' . '(Theme)';
         }
         if (empty($project['recommended'])) {
             // If we don't know what to recommend they upgrade to, we should skip
             // the project entirely.
             continue;
         }
         $recommended_release = $project['releases'][$project['recommended']];
         switch ($project['status']) {
             case UPDATE_NOT_SECURE:
             case UPDATE_REVOKED:
                 $project_name .= ' ' . '(Security update)';
                 break;
             case UPDATE_NOT_SUPPORTED:
                 $project_name .= ' ' . '(Unsupported)';
                 break;
             case UPDATE_UNKNOWN:
             case UPDATE_NOT_FETCHED:
             case UPDATE_NOT_CHECKED:
             case UPDATE_NOT_CURRENT:
                 break;
             default:
                 // Jump out of the switch and onto the next project in foreach.
                 continue 2;
         }
         // Push Return
         switch ($project['project_type']) {
             case 'core':
                 $updates[] = $this->caller->_newUpdateRow(array('update_id' => $project['project_type'] . ':' . $project['name'] . ':' . $recommended_release['version'], 'extension_id' => $project['name'], 'name' => $project_name, 'description' => $project['info']['package'], 'element' => $project['info']['project'], 'type' => $project['project_type'], 'version' => $recommended_release['version'], 'detailsurl' => $project['link'], 'infourl' => $recommended_release['release_link'], 'downloadurl' => $recommended_release['download_link'], 'installed_version' => $project['info']['version'], 'status' => 'manual'));
                 break;
             case 'module':
             case 'theme':
                 $updates[] = $this->caller->_newUpdateRow(array('update_id' => $project['project_type'] . ':' . $project['name'] . ':' . $recommended_release['version'], 'extension_id' => $project['name'], 'name' => $project_name, 'description' => $project['info']['package'], 'element' => $project['info']['project'], 'type' => $project['project_type'], 'version' => $recommended_release['version'], 'detailsurl' => $project['link'], 'infourl' => $recommended_release['release_link'], 'downloadurl' => $recommended_release['download_link'], 'installed_version' => $project['info']['version']));
                 break;
             default:
                 break;
         }
     }
     // Return
     return $updates;
 }