Update to Drupal 8.0.0-beta15. For more information, see: https://www.drupal.org/node/2563023

This commit is contained in:
Pantheon Automation 2015-09-04 13:20:09 -07:00 committed by Greg Anderson
parent 2720a9ec4b
commit f3791f1da3
1898 changed files with 54300 additions and 11481 deletions

View file

@ -13,6 +13,7 @@ use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Updater\Updater;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Response;
/**
* Configure update settings for this site.
@ -27,7 +28,7 @@ class UpdateManagerInstall extends FormBase {
protected $moduleHandler;
/**
* The app root.
* The root location under which installed projects will be saved.
*
* @var string
*/
@ -44,7 +45,7 @@ class UpdateManagerInstall extends FormBase {
* Constructs a new UpdateManagerInstall.
*
* @param string $root
* The app root.
* The root location under which installed projects will be saved.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param string $site_path
@ -68,7 +69,7 @@ class UpdateManagerInstall extends FormBase {
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('app.root'),
$container->get('update.root'),
$container->get('module_handler'),
$container->get('site.path')
);
@ -192,7 +193,7 @@ class UpdateManagerInstall extends FormBase {
$project_location = $directory . '/' . $project;
try {
$updater = Updater::factory($project_location);
$updater = Updater::factory($project_location, $this->root);
}
catch (\Exception $e) {
drupal_set_message($e->getMessage(), 'error');
@ -231,13 +232,19 @@ class UpdateManagerInstall extends FormBase {
if (fileowner($project_real_location) == fileowner($this->sitePath)) {
$this->moduleHandler->loadInclude('update', 'inc', 'update.authorize');
$filetransfer = new Local($this->root);
call_user_func_array('update_authorize_run_install', array_merge(array($filetransfer), $arguments));
$response = call_user_func_array('update_authorize_run_install', array_merge(array($filetransfer), $arguments));
if ($response instanceof Response) {
$form_state->setResponse($response);
}
}
// Otherwise, go through the regular workflow to prompt for FTP/SSH
// credentials and invoke update_authorize_run_install() indirectly with
// whatever FileTransfer object authorize.php creates for us.
else {
// The page title must be passed here to ensure it is initially used when
// authorize.php loads for the first time with the FTP/SSH credentials
// form.
system_authorized_init('update_authorize_run_install', drupal_get_path('module', 'update') . '/update.authorize.inc', $arguments, $this->t('Update manager'));
$form_state->setRedirectUrl(system_authorized_get_url());
}

View file

@ -7,7 +7,6 @@
namespace Drupal\update\Form;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
@ -115,14 +114,14 @@ class UpdateManagerUpdate extends FormBase {
$project_name = $this->l($project['title'], Url::fromUri($project['link']));
}
else {
$project_name = SafeMarkup::checkPlain($project['title']);
$project_name = $project['title'];
}
}
elseif (!empty($project['info']['name'])) {
$project_name = SafeMarkup::checkPlain($project['info']['name']);
$project_name = $project['info']['name'];
}
else {
$project_name = SafeMarkup::checkPlain($name);
$project_name = $name;
}
if ($project['project_type'] == 'theme' || $project['project_type'] == 'theme-disabled') {
$project_name .= ' ' . $this->t('(Theme)');

View file

@ -14,6 +14,7 @@ use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Updater\Updater;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Response;
/**
* Configure update settings for this site.
@ -21,7 +22,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
class UpdateReady extends FormBase {
/**
* The app root.
* The root location under which updated projects will be saved.
*
* @var string
*/
@ -52,7 +53,7 @@ class UpdateReady extends FormBase {
* Constructs a new UpdateReady object.
*
* @param string $root
* The app root.
* The root location under which updated projects will be saved.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The object that manages enabled modules in a Drupal installation.
* @param \Drupal\Core\State\StateInterface $state
@ -79,7 +80,7 @@ class UpdateReady extends FormBase {
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('app.root'),
$container->get('update.root'),
$container->get('module_handler'),
$container->get('state'),
$container->get('site.path')
@ -139,7 +140,7 @@ class UpdateReady extends FormBase {
$project_real_location = NULL;
foreach ($projects as $project => $url) {
$project_location = $directory . '/' . $project;
$updater = Updater::factory($project_location);
$updater = Updater::factory($project_location, $this->root);
$project_real_location = drupal_realpath($project_location);
$updates[] = array(
'project' => $project,
@ -156,12 +157,18 @@ class UpdateReady extends FormBase {
if (fileowner($project_real_location) == fileowner($this->sitePath)) {
$this->moduleHandler->loadInclude('update', 'inc', 'update.authorize');
$filetransfer = new Local($this->root);
update_authorize_run_update($filetransfer, $updates);
$response = update_authorize_run_update($filetransfer, $updates);
if ($response instanceof Response) {
$form_state->setResponse($response);
}
}
// Otherwise, go through the regular workflow to prompt for FTP/SSH
// credentials and invoke update_authorize_run_update() indirectly with
// whatever FileTransfer object authorize.php creates for us.
else {
// The page title must be passed here to ensure it is initially used
// when authorize.php loads for the first time with the FTP/SSH
// credentials form.
system_authorized_init('update_authorize_run_update', drupal_get_path('module', 'update') . '/update.authorize.inc', array($updates), $this->t('Update manager'));
$form_state->setRedirectUrl(system_authorized_get_url());
}

View file

@ -13,7 +13,7 @@ use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
/**
* Upgrade variables to update.settings.yml.
*
* @group update
* @group migrate_drupal_6
*/
class MigrateUpdateConfigsTest extends MigrateDrupal6TestBase {
@ -31,7 +31,6 @@ class MigrateUpdateConfigsTest extends MigrateDrupal6TestBase {
*/
protected function setUp() {
parent::setUp();
$this->loadDumps(['Variable.php']);
$this->executeMigration('d6_update_settings');
}

View file

@ -66,6 +66,7 @@ class UpdateContribTest extends UpdateTestBase {
* Tests the basic functionality of a contrib module on the status report.
*/
function testUpdateContribBasic() {
$project_link = \Drupal::l(t('AAA Update test'), Url::fromUri('http://example.com/project/aaa_update_test'));
$system_info = array(
'#all' => array(
'version' => '8.0.0',
@ -87,7 +88,30 @@ class UpdateContribTest extends UpdateTestBase {
$this->assertText(t('Up to date'));
$this->assertRaw('<h3>' . t('Modules') . '</h3>');
$this->assertNoText(t('Update available'));
$this->assertRaw(\Drupal::l(t('AAA Update test'), Url::fromUri('http://example.com/project/aaa_update_test')), 'Link to aaa_update_test project appears.');
$this->assertRaw($project_link, 'Link to aaa_update_test project appears.');
// Since aaa_update_test is installed the fact it is hidden and in the
// Testing package means it should not appear.
$system_info['aaa_update_test']['hidden'] = TRUE;
$this->config('update_test.settings')->set('system_info', $system_info)->save();
$this->refreshUpdateStatus(
array(
'drupal' => '0.0',
'aaa_update_test' => '1_0',
)
);
$this->assertNoRaw($project_link, 'Link to aaa_update_test project does not appear.');
// A hidden and installed project not in the Testing package should appear.
$system_info['aaa_update_test']['package'] = 'aaa_update_test';
$this->config('update_test.settings')->set('system_info', $system_info)->save();
$this->refreshUpdateStatus(
array(
'drupal' => '0.0',
'aaa_update_test' => '1_0',
)
);
$this->assertRaw($project_link, 'Link to aaa_update_test project appears.');
}
/**

View file

@ -22,12 +22,13 @@ class UpdateCoreTest extends UpdateTestBase {
*
* @var array
*/
public static $modules = array('update_test', 'update', 'language');
public static $modules = ['update_test', 'update', 'language', 'block'];
protected function setUp() {
parent::setUp();
$admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer modules', 'administer themes'));
$this->drupalLogin($admin_user);
$this->drupalPlaceBlock('local_actions_block');
}
/**

View file

@ -21,6 +21,7 @@
namespace Drupal\update\Tests;
use Drupal\Core\DrupalKernel;
use Drupal\Core\Url;
use Drupal\simpletest\WebTestBase;
@ -29,6 +30,29 @@ use Drupal\simpletest\WebTestBase;
*/
abstract class UpdateTestBase extends WebTestBase {
protected function setUp() {
parent::setUp();
// Change the root path which Update Manager uses to install and update
// projects to be inside the testing site directory. See
// \Drupal\update\UpdateRootFactory::get() for equivalent changes to the
// test child site.
$request = \Drupal::request();
$update_root = $this->container->get('update.root') . '/' . DrupalKernel::findSitePath($request);
$this->container->set('update.root', $update_root);
\Drupal::setContainer($this->container);
// Create the directories within the root path within which the Update
// Manager will install projects.
foreach (drupal_get_updaters() as $updater_info) {
$updater = $updater_info['class'];
$install_directory = $update_root . '/' . $updater::getRootDirectoryRelativePath();
if (!is_dir($install_directory)) {
mkdir($install_directory);
}
}
}
/**
* Refreshes the update status based on the desired available update scenario.
*

View file

@ -7,6 +7,7 @@
namespace Drupal\update\Tests;
use Drupal\Core\Extension\InfoParserDynamic;
use Drupal\Core\Updater\Updater;
use Drupal\Core\Url;
@ -26,12 +27,12 @@ class UpdateUploadTest extends UpdateTestBase {
protected function setUp() {
parent::setUp();
$admin_user = $this->drupalCreateUser(array('administer software updates', 'administer site configuration'));
$admin_user = $this->drupalCreateUser(array('administer modules', 'administer software updates', 'administer site configuration'));
$this->drupalLogin($admin_user);
}
/**
* Tests upload and extraction of a module.
* Tests upload, extraction, and update of a module.
*/
public function testUploadModule() {
// Images are not valid archives, so get one and try to install it. We
@ -46,6 +47,7 @@ class UpdateUploadTest extends UpdateTestBase {
// 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
@ -56,6 +58,74 @@ class UpdateUploadTest extends UpdateTestBase {
);
$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 = drupal_get_path('module', 'update') . '/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');
}
/**

View file

@ -51,10 +51,6 @@ interface UpdateManagerInterface {
* 'theme'.
* - project_status: This indicates if the project is enabled and will
* always be TRUE, as the function only returns enabled projects.
* - sub_themes: If the project is a theme it contains an associative array
* of all sub-themes.
* - base_themes: If the project is a theme it contains an associative array
* of all base-themes.
*
* @see update_process_project_info()
* @see update_calculate_project_data()

View file

@ -0,0 +1,77 @@
<?php
/**
* @file
* Contains \Drupal\update\UpdateRootFactory.
*/
namespace Drupal\update;
use Drupal\Core\DrupalKernelInterface;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Gets the root path used by the Update Manager to install or update projects.
*/
class UpdateRootFactory {
/**
* The Drupal kernel.
*
* @var \Drupal\Core\DrupalKernelInterface
*/
protected $drupalKernel;
/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* Constructs an UpdateRootFactory instance.
*
* @param \Drupal\Core\DrupalKernelInterface $drupal_kernel
* The Drupal kernel.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
*/
public function __construct(DrupalKernelInterface $drupal_kernel, RequestStack $request_stack) {
$this->drupalKernel = $drupal_kernel;
$this->requestStack = $request_stack;
}
/**
* Gets the root path under which projects are installed or updated.
*
* The Update Manager will ensure that project files can only be copied to
* specific subdirectories of this root path.
*
* @return string
*/
public function get() {
// Normally the Update Manager's root path is the same as the app root (the
// directory in which the Drupal site is installed).
$root_path = $this->drupalKernel->getAppRoot();
// When running in a test site, change the root path to be the testing site
// directory. This ensures that it will always be writable by the webserver
// (thereby allowing the actual extraction and installation of projects by
// the Update Manager to be tested) and also ensures that new project files
// added there won't be visible to the parent site and will be properly
// cleaned up once the test finishes running. This is done here (rather
// than having the tests enable a module which overrides the update root
// factory service) to ensure that the parent site is automatically kept
// clean without relying on test authors to take any explicit steps. See
// also \Drupal\update\Tests\UpdateTestBase::setUp().
if (DRUPAL_TEST_IN_CHILD_SITE) {
$kernel = $this->drupalKernel;
$request = $this->requestStack->getCurrentRequest();
$root_path .= '/' . $kernel::findSitePath($request);
}
return $root_path;
}
}

View file

@ -21,8 +21,6 @@
* - data: The data about an extra item.
* - includes: The projects within the project.
* - disabled: The currently disabled projects in the project.
* - base_themes: The base themes supplied by the project.
* - sub_themes: The subthemes supplied by the project.
*
* @see template_preprocess_update_project_status()
*
@ -105,18 +103,4 @@
Includes: {{ includes|placeholder }}
{% endtrans %}
{% endif %}
{% if base_themes %}
{% set basethemes = base_themes|join(', ') %}
{% trans %}
Depends on: {{ basethemes }}
{% endtrans %}
{% endif %}
{% if sub_themes %}
{% set subthemes = sub_themes|join(', ') %}
{% trans %}
Required by: {{ subthemes|placeholder }}
{% endtrans %}
{% endif %}
</div>

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<project xmlns:dc="http://purl.org/dc/elements/1.1/">
<title>Update test new module</title>
<short_name>update_test_new_module</short_name>
<dc:creator>Drupal</dc:creator>
<api_version>8.x</api_version>
<recommended_major>1</recommended_major>
<supported_majors>1</supported_majors>
<default_major>1</default_major>
<project_status>published</project_status>
<link>http://example.com/project/update_test_new_module</link>
<terms>
<term><name>Projects</name><value>Modules</value></term>
</terms>
<releases>
<release>
<name>update_test_new_module 8.x-1.1</name>
<version>8.x-1.1</version>
<tag>DRUPAL-8--1-1</tag>
<version_major>1</version_major>
<version_patch>1</version_patch>
<status>published</status>
<release_link>http://example.com/update_test_new_module-8-x-1-1-release</release_link>
<download_link>core/modules/update/tests/update_test_new_module/8.x-1.1/update_test_new_module.tar.gz</download_link>
<date>1300424521</date>
<mdhash>b966255555d9c9b86d480ca08cfaa98e</mdhash>
<filesize>1073741824</filesize>
<terms>
<term><name>Release type</name><value>New features</value></term>
<term><name>Release type</name><value>Bug fixes</value></term>
</terms>
</release>
</releases>
</project>

View file

@ -11,6 +11,7 @@
*/
use Drupal\Core\Updater\UpdaterException;
use Drupal\Core\Url;
/**
* Updates existing projects when invoked by authorize.php.
@ -28,6 +29,11 @@ use Drupal\Core\Updater\UpdaterException;
* - updater_name: The name of the Drupal\Core\Updater\Updater class to use
* for this project.
* - local_url: The locally installed location of new code to update with.
*
* @return \Symfony\Component\HttpFoundation\Response|null
* The result of processing the batch that updates the projects. If this is
* an instance of \Symfony\Component\HttpFoundation\Response the calling code
* should use that response for the current page request.
*/
function update_authorize_run_update($filetransfer, $projects) {
$operations = array();
@ -44,14 +50,18 @@ function update_authorize_run_update($filetransfer, $projects) {
}
$batch = array(
'title' => t('Installing updates'),
'init_message' => t('Preparing to update your site'),
'operations' => $operations,
'finished' => 'update_authorize_update_batch_finished',
'file' => drupal_get_path('module', 'update') . '/update.authorize.inc',
);
batch_set($batch);
// Since authorize.php has its own method for setting the page title, set it
// manually here rather than passing it in to batch_set() as would normally
// be done.
$_SESSION['authorize_page_title'] = t('Installing updates');
// Invoke the batch via authorize.php.
return system_authorized_batch_process();
}
@ -74,6 +84,11 @@ function update_authorize_run_update($filetransfer, $projects) {
* @param string $local_url
* The URL to the locally installed temp directory where the project has
* already been downloaded and extracted into.
*
* @return \Symfony\Component\HttpFoundation\Response|null
* The result of processing the batch that installs the project. If this is
* an instance of \Symfony\Component\HttpFoundation\Response the calling code
* should use that response for the current page request.
*/
function update_authorize_run_install($filetransfer, $project, $updater_name, $local_url) {
$operations[] = array(
@ -88,7 +103,6 @@ function update_authorize_run_install($filetransfer, $project, $updater_name, $l
// @todo Instantiate our Updater to set the human-readable title?
$batch = array(
'title' => t('Installing %project', array('%project' => $project)),
'init_message' => t('Preparing to install'),
'operations' => $operations,
// @todo Use a different finished callback for different messages?
@ -97,6 +111,11 @@ function update_authorize_run_install($filetransfer, $project, $updater_name, $l
);
batch_set($batch);
// Since authorize.php has its own method for setting the page title, set it
// manually here rather than passing it in to batch_set() as would normally
// be done.
$_SESSION['authorize_page_title'] = t('Installing %project', array('%project' => $project));
// Invoke the batch via authorize.php.
return system_authorized_batch_process();
}
@ -147,7 +166,7 @@ function update_authorize_batch_copy_project($project, $updater_name, $local_url
return;
}
$updater = new $updater_name($local_url);
$updater = new $updater_name($local_url, \Drupal::getContainer()->get('update.root'));
try {
if ($updater->isInstalled()) {
@ -229,7 +248,19 @@ function update_authorize_update_batch_finished($success, $results) {
// Since we're doing an update of existing code, always add a task for
// running update.php.
$results['tasks'][] = t('Your modules have been downloaded and updated.');
$results['tasks'][] = t('<a href="@update">Run database updates</a>', array('@update' => \Drupal::url('system.db_update')));
$results['tasks'][] = [
'#type' => 'link',
'#url' => Url::fromRoute('system.db_update'),
'#title' => t('Run database updates'),
// Since this is being called outsite of the primary front controller,
// the base_url needs to be set explicitly to ensure that links are
// relative to the site root.
// @todo Simplify with https://www.drupal.org/node/2548095
'#options' => [
'absolute' => TRUE,
'base_url' => $GLOBALS['base_url'],
],
];
// Unset the variable since it is no longer needed.
unset($_SESSION['maintenance_mode']);
@ -239,6 +270,7 @@ function update_authorize_update_batch_finished($success, $results) {
$_SESSION['authorize_results']['page_message'] = $page_message;
$_SESSION['authorize_results']['messages'] = $results['log'];
$_SESSION['authorize_results']['tasks'] = $results['tasks'];
$_SESSION['authorize_page_title'] = t('Update manager');
}
/**
@ -299,6 +331,7 @@ function update_authorize_install_batch_finished($success, $results) {
$_SESSION['authorize_results']['page_message'] = $page_message;
$_SESSION['authorize_results']['messages'] = $results['log'];
$_SESSION['authorize_results']['tasks'] = $results['tasks'];
$_SESSION['authorize_page_title'] = t('Update manager');
}
/**

View file

@ -107,8 +107,17 @@ function _update_requirement_check($project, $type) {
$status = $project['status'];
if ($status != UPDATE_CURRENT) {
$requirement['reason'] = $status;
$requirement['description'] = _update_message_text($type, $status, TRUE);
$requirement['severity'] = REQUIREMENT_ERROR;
// Append the available updates link to the message from
// _update_message_text(), and format the two translated strings together in
// a single paragraph.
$requirement['description'][] = ['#markup' => _update_message_text($type, $status)];
if (_update_manager_access()) {
$requirement['description'][] = ['#prefix' => ' ', '#markup' => t('See the <a href="@available_updates">available updates</a> page for more information and to install your missing updates.', ['@available_updates' => \Drupal::url('update.report_update')])];
}
else {
$requirement['description'][] = ['#prefix' => ' ', '#markup' => t('See the <a href="@available_updates">available updates</a> page for more information.', ['@available_updates' => \Drupal::url('update.status')])];
}
}
switch ($status) {
case UPDATE_NOT_SECURE:
@ -136,6 +145,6 @@ function _update_requirement_check($project, $type) {
if ($status != UPDATE_CURRENT && $type == 'core' && isset($project['recommended'])) {
$requirement_label .= ' ' . t('(version @version available)', array('@version' => $project['recommended']));
}
$requirement['value'] = \Drupal::l($requirement_label, new Url(update_manager_access() ? 'update.report_update' : 'update.status'));
$requirement['value'] = \Drupal::l($requirement_label, new Url(_update_manager_access() ? 'update.report_update' : 'update.status'));
return $requirement;
}

View file

@ -206,7 +206,7 @@ function update_manager_archive_verify($project, $archive_file, $directory) {
function update_manager_file_get($url) {
$parsed_url = parse_url($url);
$remote_schemes = array('http', 'https', 'ftp', 'ftps', 'smb', 'nfs');
if (!in_array($parsed_url['scheme'], $remote_schemes)) {
if (!isset($parsed_url['scheme']) || !in_array($parsed_url['scheme'], $remote_schemes)) {
// This is a local file, just return the path.
return drupal_realpath($url);
}

View file

@ -11,7 +11,6 @@
* ability to install contributed modules and themes via an user interface.
*/
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Url;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
@ -75,7 +74,7 @@ function update_help($route_name, RouteMatchInterface $route_match) {
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Update Manager module periodically checks for new versions of your site\'s software (including contributed modules and themes), and alerts administrators to available updates. The Update Manager system is also used by some other modules to manage updates and downloads; for example, the Interface Translation module uses the Update Manager to download translations from the localization server. Note that whenever the Update Manager system is used, anonymous usage statistics are sent to Drupal.org. If desired, you may disable the Update Manager module from the <a href="!modules">Extend page</a>; if you do so, functionality that depends on the Update Manager system will not work. For more information, see <a href="!update">the online documentation for the Update Manager module</a>.', array('!update' => 'https://www.drupal.org/documentation/modules/update', '!modules' => \Drupal::url('system.modules_list'))) . '</p>';
// Only explain the Update manager if it has not been disabled.
if (update_manager_access()) {
if (_update_manager_access()) {
$output .= '<p>' . t('The Update Manager also allows administrators to update and install modules and themes through the administration interface.') . '</p>';
}
$output .= '<h3>' . t('Uses') . '</h3>';
@ -83,7 +82,7 @@ function update_help($route_name, RouteMatchInterface $route_match) {
$output .= '<dt>' . t('Checking for available updates') . '</dt>';
$output .= '<dd>' . t('The <a href="!update-report">Available updates report</a> displays core, contributed modules, and themes for which there are new releases available for download. On the report page, you can also check manually for updates. You can configure the frequency of update checks, which are performed during cron runs, and whether notifications are sent on the <a href="!update-settings">Update Manager settings page</a>.', array('!update-report' => \Drupal::url('update.status'), '!update-settings' => \Drupal::url('update.settings'))) . '</dd>';
// Only explain the Update manager if it has not been disabled.
if (update_manager_access()) {
if (_update_manager_access()) {
$output .= '<dt>' . t('Performing updates through the Update page') . '</dt>';
$output .= '<dd>' . t('The Update Manager module allows administrators to perform updates directly from the <a href="!update-page">Update page</a>. It lists all available updates, and you can confirm whether you want to download them. If you don\'t have sufficient access rights to your web server, you could be prompted for your FTP/SSH password. Afterwards the files are transferred into your site installation, overwriting your old files. Direct links to the Update page are also displayed on the <a href="!modules_page">Extend page</a> and the <a href="!themes_page">Appearance page</a>.', array('!modules_page' => \Drupal::url('system.modules_list'), '!themes_page' => \Drupal::url('system.themes_page'), '!update-page' => \Drupal::url('update.report_update'))) . '</dd>';
$output .= '<dt>' . t('Installing new modules and themes through the Install page') . '</dt>';
@ -94,6 +93,15 @@ function update_help($route_name, RouteMatchInterface $route_match) {
case 'update.status':
return '<p>' . t('Here you can find information about available updates for your installed modules and themes. Note that each module or theme is part of a "project", which may or may not have the same name, and might include multiple modules or themes within it.') . '</p>';
case 'system.modules_list':
if (_update_manager_access()) {
$output = '<p>' . t('Regularly review and install <a href="!updates">available updates</a> to maintain a secure and current site. Always run the <a href="!update-php">update script</a> each time a module is updated.', array('!update-php' => \Drupal::url('system.db_update'), '!updates' => \Drupal::url('update.status'))) . '</p>';
}
else {
$output = '<p>' . t('Regularly review <a href="!updates">available updates</a> to maintain a secure and current site. Always run the <a href="!update-php">update script</a> each time a module is updated.', array('!update-php' => \Drupal::url('system.db_update'), '!updates' => \Drupal::url('update.status'))) . '</p>';
}
return $output;
}
}
@ -156,7 +164,7 @@ function update_page_top() {
}
/**
* Access callback: Resolves if the current user can access updater menu items.
* Resolves if the current user can access updater menu items.
*
* It both enforces the 'administer software updates' permission and the global
* kill switch for the authorize.php script.
@ -164,10 +172,8 @@ function update_page_top() {
* @return
* TRUE if the current user can access the updater menu items; FALSE
* otherwise.
*
* @see update_menu()
*/
function update_manager_access() {
function _update_manager_access() {
return Settings::get('allow_authorize_operations', TRUE) && \Drupal::currentUser()->hasPermission('administer software updates');
}
@ -184,7 +190,7 @@ function update_theme() {
'file' => 'update.report.inc',
),
'update_project_status' => array(
'variables' => array('project' => array(), 'includes_status' => array()),
'variables' => array('project' => array()),
'file' => 'update.report.inc',
),
// We are using template instead of '#type' => 'table' here to keep markup
@ -437,10 +443,10 @@ function update_mail($key, &$message, $params) {
$language = \Drupal::languageManager()->getLanguage($langcode);
$message['subject'] .= t('New release(s) available for !site_name', array('!site_name' => \Drupal::config('system.site')->get('name')), array('langcode' => $langcode));
foreach ($params as $msg_type => $msg_reason) {
$message['body'][] = _update_message_text($msg_type, $msg_reason, FALSE, $langcode);
$message['body'][] = _update_message_text($msg_type, $msg_reason, $langcode);
}
$message['body'][] = t('See the available updates page for more information:', array(), array('langcode' => $langcode)) . "\n" . \Drupal::url('update.status', [], ['absolute' => TRUE, 'language' => $language]);
if (update_manager_access()) {
if (_update_manager_access()) {
$message['body'][] = t('You can automatically install your missing updates using the Update manager:', array(), array('langcode' => $langcode)) . "\n" . \Drupal::url('update.report_update', [], ['absolute' => TRUE, 'language' => $language]);
}
$settings_url = \Drupal::url('update.settings', [], ['absolute' => TRUE]);
@ -464,16 +470,13 @@ function update_mail($key, &$message, $params) {
* or 'contrib'.
* @param $msg_reason
* Integer constant specifying why message is generated.
* @param $report_link
* (optional) Boolean that controls if a link to the updates report should be
* added. Defaults to FALSE.
* @param $langcode
* (optional) A language code to use. Defaults to NULL.
*
* @return
* The properly translated error message for the given key.
*/
function _update_message_text($msg_type, $msg_reason, $report_link = FALSE, $langcode = NULL) {
function _update_message_text($msg_type, $msg_reason, $langcode = NULL) {
$text = '';
switch ($msg_reason) {
case UPDATE_NOT_SECURE:
@ -524,23 +527,8 @@ function _update_message_text($msg_type, $msg_reason, $report_link = FALSE, $lan
}
break;
}
if (!empty($langcode)) {
$language = \Drupal::languageManager()->getLanguage($langcode);
}
else {
$language = NULL;
}
if ($report_link) {
if (update_manager_access()) {
$text .= ' ' . t('See the <a href="@available_updates">available updates</a> page for more information and to install your missing updates.', array('@available_updates' => \Drupal::url('update.report_update', [], ['language' => $language])), array('langcode' => $langcode));
}
else {
$text .= ' ' . t('See the <a href="@available_updates">available updates</a> page for more information.', array('@available_updates' => \Drupal::url('update.status', [], ['language' => $language])), array('langcode' => $langcode));
}
}
// All strings are t() and empty space concatenated so return SafeMarkup.
return SafeMarkup::set($text);
return $text;
}
/**

View file

@ -39,24 +39,12 @@ function template_preprocess_update_report(&$variables) {
$variables['no_updates_message'] = _update_no_data();
}
$status = array();
// 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'];
}
}
$rows = array();
foreach ($data as $project) {
$project_status = array(
'#theme' => 'update_project_status',
'#project' => $project,
'#includes_status' => $status,
);
// Build project rows.
@ -74,6 +62,8 @@ function template_preprocess_update_report(&$variables) {
// Add project status class attribute to the table row.
switch ($project['status']) {
case UPDATE_CURRENT:
$rows[$project['project_type']][$row_key]['#attributes'] = array('class' => array('color-success'));
break;
case UPDATE_UNKNOWN:
case UPDATE_FETCH_PENDING:
case UPDATE_NOT_FETCHED:
@ -118,14 +108,10 @@ function template_preprocess_update_report(&$variables) {
* @param array $variables
* An associative array containing:
* - project: An array of information about the project.
* - includes_status: An array of sub-project statuses where the keys are the
* shortnames of each project and the values are UPDATE_* integer constants
* as defined in update.module.
*/
function template_preprocess_update_project_status(&$variables) {
// Storing by reference because we are sorting the project values.
$project = &$variables['project'];
$includes_status = $variables['includes_status'];
// Set the project title and URL.
$variables['title'] = (isset($project['title'])) ? $project['title'] : $project['name'];
@ -242,47 +228,15 @@ function template_preprocess_update_project_status(&$variables) {
$extra_item = array();
$extra_item['attributes'] = new Attribute();
$extra_item['label'] = $value['label'];
$extra_item['data'] = drupal_placeholder($value['data']);
$extra_item['data'] = [
'#prefix' => '<em>',
'#markup' => $value['data'],
'#suffix' => '</em>'
];
$variables['extras'][] = $extra_item;
}
}
if (!empty($project['base_themes'])) {
asort($project['base_themes']);
$base_themes = array();
foreach ($project['base_themes'] as $base_key => $base_theme) {
switch ($includes_status[$base_key]) {
case UPDATE_NOT_SECURE:
$base_status_label = t('Security update required!');
break;
case UPDATE_REVOKED:
$base_status_label = t('Revoked!');
break;
case UPDATE_NOT_SUPPORTED:
$base_status_label = t('Not supported!');
break;
default:
$base_status_label = '';
}
if ($base_status_label) {
$base_themes[] = t('%base_theme (!base_label)', array(
'%base_theme' => $base_theme,
'!base_label' => $base_status_label,
));
}
else {
$base_themes[] = drupal_placeholder($base_theme);
}
}
$variables['base_themes'] = $base_themes;
}
if (!empty($project['sub_themes'])) {
sort($project['sub_themes']);
$variables['sub_themes'] = $project['sub_themes'];
}
// Set the project status details.
$status_label = NULL;
switch ($project['status']) {
@ -320,7 +274,7 @@ function template_preprocess_update_project_status(&$variables) {
case UPDATE_NOT_SECURE:
case UPDATE_REVOKED:
case UPDATE_NOT_SUPPORTED:
$uri = 'core/misc/icons/ea2800/error.svg';
$uri = 'core/misc/icons/e32700/error.svg';
$text = t('Error');
break;
case UPDATE_NOT_CHECKED:

View file

@ -13,3 +13,12 @@ services:
update.fetcher:
class: Drupal\update\UpdateFetcher
arguments: ['@config.factory', '@http_client']
update.root:
class: SplString
factory: update.root.factory:get
tags:
- { name: parameter_service }
update.root.factory:
class: Drupal\update\UpdateRootFactory
arguments: ['@kernel', '@request_stack']
public: false