'description'=>t('Update notifications are not enabled. It is <strong>highly recommended</strong> that you enable the Update Manager module from the <a href=":module">module administration page</a> in order to stay up-to-date on new releases. For more information, <a href=":update">Update status handbook page</a>.',[
'#markup'=>$this->t('You can find <a href=":module_url">modules</a> and <a href=":theme_url">themes</a> on <a href=":drupal_org_url">drupal.org</a>. The following file extensions are supported: %extensions.',[
'major_update_warning_text'=>$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.'),
'#markup'=>$this->t('Back up your database and site before you continue. <a href=":backup_url">Learn how</a>.',[':backup_url'=>'https://www.drupal.org/node/22281']),
'#suffix'=>'</strong>',
];
$form['maintenance_mode']=[
'#title'=>$this->t('Perform updates with site in maintenance mode (strongly recommended)'),
@trigger_error(__NAMESPACE__.'\UpdateTestBase is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, use \Drupal\Tests\update\Functional\UpdateTestBase',E_USER_DEPRECATED);
useDrupal\Core\DrupalKernel;
useDrupal\Core\Url;
useDrupal\simpletest\WebTestBase;
/**
* Defines some shared functions used by all update tests.
*
* The overarching methodology of these tests is we need to compare a given
* state of installed modules and themes (e.g., version, project grouping,
* timestamps, etc) against a current state of what the release history XML
* files we fetch say is available. We have dummy XML files (in the
* core/modules/update/tests directory) that describe various scenarios of
* what's available for different test projects, and we have dummy .info file
* data (specified via hook_system_info_alter() in the update_test helper
* module) describing what's currently installed. Each test case defines a set
* of projects to install, their current state (via the
* 'update_test_system_info' variable) and the desired available update data
* (via the 'update_test_xml_map' variable), and then performs a series of
* assertions that the report matches our expectations given the specific
* initial state and availability scenario.
*
* @deprecated Scheduled for removal in Drupal 9.0.0.
* Use \Drupal\Tests\update\Functional\UpdateTestBase instead.
*/
abstractclassUpdateTestBaseextendsWebTestBase{
protectedfunctionsetUp(){
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
'#description'=>t('Whenever your site checks for available updates and finds new releases, it can notify a list of users via email. Put each address on a separate line. If blank, no emails will be sent.'),
'#description'=>t('You can choose to send email only if a security update is available, or to be notified about all newer versions. If there are updates available of Drupal core or any of your installed modules and themes, your site will always print a message on the <a href=":status_report">status report</a> page, and will also display an error message on administration pages if there is a security update.',[':status_report'=>$this->url('system.status')]),
// We're expecting the report to say all projects are up to date.
$this->assertText(t('Up to date'));
$this->assertNoText(t('Update available'));
// We want to see all 3 module names listed, since they'll show up either
// as project names or as modules under the "Includes" listing.
$this->assertText(t('AAA Update test'));
$this->assertText(t('BBB Update test'));
$this->assertText(t('CCC Update test'));
// We want aaa_update_test included in the ccc_update_test project, not as
// its own project on the report.
$this->assertNoRaw(\Drupal::l(t('AAA Update test'),Url::fromUri('http://example.com/project/aaa_update_test')),'Link to aaa_update_test project does not appear.');
// The other two should be listed as projects.
$this->assertRaw(\Drupal::l(t('BBB Update test'),Url::fromUri('http://example.com/project/bbb_update_test')),'Link to bbb_update_test project appears.');
$this->assertRaw(\Drupal::l(t('CCC Update test'),Url::fromUri('http://example.com/project/ccc_update_test')),'Link to bbb_update_test project appears.');
// We want to make sure we see the BBB project before the CCC project.
// Instead of just searching for 'BBB Update test' or something, we want
// to use the full markup that starts the project entry itself, so that
// we're really testing that the project listings are in the right order.
$this->assertTrue(strpos($this->getSession()->getPage()->getContent(),$bbb_project_link)<strpos($this->getSession()->getPage()->getContent(),$ccc_project_link),"'BBB Update test' project is listed before the 'CCC Update test' project");
}
/**
* Tests that subthemes are notified about security updates for base themes.
$this->assertRaw(\Drupal::l(t('Update test base theme'),Url::fromUri('http://example.com/project/update_test_basetheme')),'Link to the Update test base theme project appears.');
}
/**
* Tests that disabled themes are only shown when desired.
*
* @todo https://www.drupal.org/node/2338175 extensions can not be hidden and
// Ensure that the update information is correct before testing.
$this->drupalGet('admin/reports/updates');
$xml_mapping=[
'drupal'=>'0.0',
'aaa_update_test'=>'1_0',
'bbb_update_test'=>'does-not-exist',
'ccc_update_test'=>'1_0',
];
$this->refreshUpdateStatus($xml_mapping);
$this->assertText(t('Up to date'));
// We're expecting the report to say most projects are up to date, so we
// hope that 'Up to date' is not unique.
$this->assertNoUniqueText(t('Up to date'));
// It should say we failed to get data, not that we're missing an update.
$this->assertNoText(t('Update available'));
// We need to check that this string is found as part of a project row, not
// just in the "Failed to get available update data" message at the top of
// the page.
$this->assertRaw('<div class="project-update__status">'.t('Failed to get available update data'));
// We should see the output messages from fetching manually.
$this->assertUniqueText(t('Checked available update data for 3 projects.'));
$this->assertUniqueText(t('Failed to get available update data for one project.'));
// The other two should be listed as projects.
$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->assertNoRaw(\Drupal::l(t('BBB Update test'),Url::fromUri('http://example.com/project/bbb_update_test')),'Link to bbb_update_test project does not appear.');
$this->assertRaw(\Drupal::l(t('CCC Update test'),Url::fromUri('http://example.com/project/ccc_update_test')),'Link to bbb_update_test project appears.');
}
/**
* Checks that hook_update_status_alter() works to change a status.
*
* We provide the same external data as if aaa_update_test 8.x-1.0 were
* installed and that was the latest release. Then we use
* hook_update_status_alter() to try to mark this as missing a security
* update, then assert if we see the appropriate warnings on the right pages.
$this->assertRaw(\Drupal::l("8.$minor_version.1".$extra_version,Url::fromUri("http://example.com/drupal-8-$minor_version-1$extra_version-release")),'Link to release appears.');
$this->assertRaw(\Drupal::l(t('Download'),Url::fromUri("http://example.com/drupal-8-$minor_version-1$extra_version.tar.gz")),'Link to download appears.');
$this->assertRaw(\Drupal::l(t('Release notes'),Url::fromUri("http://example.com/drupal-8-$minor_version-1$extra_version-release")),'Link to release notes appears.');
switch($minor_version){
case0:
// Both stable and unstable releases are available.
// A stable release is the latest.
if($extra_version==''){
$this->assertNoText(t('Up to date'));
$this->assertText(t('Update available'));
$this->assertText(t('Recommended version:'));
$this->assertNoText(t('Latest version:'));
$this->assertRaw('warning.svg','Warning icon was found.');
}
// Only unstable releases are available.
// An unstable release is the latest.
else{
$this->assertText(t('Up to date'));
$this->assertNoText(t('Update available'));
$this->assertNoText(t('Recommended version:'));
$this->assertText(t('Latest version:'));
$this->assertRaw('check.svg','Check icon was found.');
}
break;
case1:
// Both stable and unstable releases are available.
// A stable release is the latest.
if($extra_version==''){
$this->assertNoText(t('Up to date'));
$this->assertText(t('Update available'));
$this->assertText(t('Recommended version:'));
$this->assertNoText(t('Latest version:'));
$this->assertRaw('warning.svg','Warning icon was found.');
}
// Both stable and unstable releases are available.
// An unstable release is the latest.
else{
$this->assertNoText(t('Up to date'));
$this->assertText(t('Update available'));
$this->assertText(t('Recommended version:'));
$this->assertText(t('Latest version:'));
$this->assertRaw('warning.svg','Warning icon was found.');
}
break;
}
}
}
}
/**
* Tests the Update Manager module when a major update is available.
$this->assertText(t('Only files with the following extensions are allowed: @archive_extensions.',['@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
$this->assertFalse(file_exists($installedInfoFilePath),'The new module does not exist in the filesystem before it is installed with the Update Manager.');
// If the project status is marked as something bad, there's nothing else
// to consider.
if(isset($available['project_status'])){
switch($available['project_status']){
case'insecure':
$project_data['status']=UPDATE_NOT_SECURE;
if(empty($project_data['extra'])){
$project_data['extra']=[];
}
$project_data['extra'][]=[
'label'=>t('Project not secure'),
'data'=>t('This project has been labeled insecure by the Drupal security team, and is no longer available for download. Immediately disabling everything included by this project is strongly recommended!'),
];
break;
case'unpublished':
case'revoked':
$project_data['status']=UPDATE_REVOKED;
if(empty($project_data['extra'])){
$project_data['extra']=[];
}
$project_data['extra'][]=[
'label'=>t('Project revoked'),
'data'=>t('This project has been revoked, and is no longer available for download. Disabling everything included by this project is strongly recommended!'),
];
break;
case'unsupported':
$project_data['status']=UPDATE_NOT_SUPPORTED;
if(empty($project_data['extra'])){
$project_data['extra']=[];
}
$project_data['extra'][]=[
'label'=>t('Project not supported'),
'data'=>t('This project is no longer supported, and is no longer available for download. Disabling everything included by this project is strongly recommended!'),
];
break;
case'not-fetched':
$project_data['status']=UPDATE_NOT_FETCHED;
$project_data['reason']=t('Failed to get available update data.');
break;
default:
// Assume anything else (e.g. 'published') is valid and we should
// perform the rest of the logic in this function.
break;
}
}
if(!empty($project_data['status'])){
// We already know the status for this project, so there's nothing else to
// compute. Record the project status into $project_data and we're done.
'data'=>t('Your currently installed release has been revoked, and is no longer available for download. Disabling everything included in this release or upgrading is strongly recommended!'),
'data'=>t('Your currently installed release is now unsupported, and is no longer available for download. Disabling everything included in this release or upgrading is strongly recommended!'),
];
}
}
// Otherwise, ignore unpublished, insecure, or unsupported releases.
$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){
caseUPDATE_NOT_SECURE:
$requirement_label=t('Not secure!');
break;
caseUPDATE_REVOKED:
$requirement_label=t('Revoked!');
break;
caseUPDATE_NOT_SUPPORTED:
$requirement_label=t('Unsupported release');
break;
caseUPDATE_NOT_CURRENT:
$requirement_label=t('Out of date');
$requirement['severity']=REQUIREMENT_WARNING;
break;
caseUPDATE_UNKNOWN:
caseUPDATE_NOT_CHECKED:
caseUPDATE_NOT_FETCHED:
caseUPDATE_FETCH_PENDING:
$requirement_label=isset($project['reason'])?$project['reason']:t('Can not determine status');
$form['available_backends']['#markup']=t('Your server does not support updating modules and themes from this interface. Instead, update modules and themes by uploading the new versions directly to the server, as documented in <a href=":doc_url">Extending Drupal 8</a>.',[':doc_url'=>'https://www.drupal.org/docs/8/extending-drupal-8/overview']);
}
else{
$form['available_backends']['#markup']=t('Your server does not support installing modules and themes from this interface. Instead, install modules and themes by uploading them directly to the server, as documented in <a href=":doc_url">Extending Drupal 8</a>.',[':doc_url'=>'https://www.drupal.org/docs/8/extending-drupal-8/overview']);
'Updating modules and themes requires <strong>@backends access</strong> to your server. See <a href=":doc_url">Extending Drupal 8</a> for other update methods.',
'Updating modules and themes requires access to your server via one of the following methods: <strong>@backends</strong>. See <a href=":doc_url">Extending Drupal 8</a> for other update methods.',
'Installing modules and themes requires <strong>@backends access</strong> to your server. See <a href=":doc_url">Extending Drupal 8</a> for other installation methods.',
'Installing modules and themes requires access to your server via one of the following methods: <strong>@backends</strong>. See <a href=":doc_url">Extending Drupal 8</a> for other installation methods.',
$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 the <a href=":update">online documentation for the Update Manager module</a>.',[':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()){
$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>';
$output.='<dl>';
$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>.',[':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()){
$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>.',[':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>';
$output.='<dd>'.t('You can also install new modules and themes in the same fashion, through the <a href=":install">Install page</a>, or by clicking the <em>Install new module/theme</em> links at the top of the <a href=":modules_page">Extend page</a> and the <a href=":themes_page">Appearance page</a>. In this case, you are prompted to provide either the URL to the download, or to upload a packaged release file from your local computer.',[':modules_page'=>\Drupal::url('system.modules_list'),':themes_page'=>\Drupal::url('system.themes_page'),':install'=>\Drupal::url('update.report_install')]).'</dd>';
}
$output.='</dl>';
return$output;
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.',[':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.',[':update-php'=>\Drupal::url('system.db_update'),':updates'=>\Drupal::url('update.status')]).'</p>';
* Identifies equivalent security releases with a hardcoded list.
*
* Generally, only the latest minor version of Drupal 8 is supported. However,
* when security fixes are backported to an old branch, and the site owner
* updates to the release containing the backported fix, they should not
* see "Security update required!" again if the only other security releases
* are releases for the same advisories.
*
* @return string[]
* A list of security release numbers that are equivalent to this release
* (i.e. covered by the same advisory), for backported security fixes only.
*
* @internal
*
* @deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Use the
* 'Insecure' release type tag in update XML provided by Drupal.org to
* determine if releases are insecure.
*/
function_update_equivalent_security_releases(){
trigger_error("_update_equivalent_security_releases() was a temporary fix and will be removed before 9.0.0. Use the 'Insecure' release type tag in update XML provided by Drupal.org to determine if releases are insecure.",E_USER_DEPRECATED);
switch(\Drupal::VERSION){
case'8.3.8':
return['8.4.5','8.5.0-rc1'];
case'8.3.9':
return['8.4.6','8.5.1'];
case'8.4.5':
return['8.5.0-rc1'];
case'8.4.6':
return['8.5.1'];
case'8.4.7':
return['8.5.2'];
case'8.4.8':
return['8.5.3'];
}
return[];
}
/**
* Adds a task to the queue for fetching release history data for a project.
*
* We only create a new fetch task if there's no task already in the queue for
* this particular project (based on 'update_fetch_task' key-value collection).
*
* @param $project
* Associative array of information about a project as created by
* \Drupal\Update\UpdateManager::getProjects(), including keys such as 'name'
* (short name), and the 'info' array with data from a .info.yml file for the
\Drupal::messenger()->addStatus(\Drupal::translation()->formatPlural($results['updated'],'Checked available update data for one project.','Checked available update data for @count projects.'));
}
if(!empty($results['failures'])){
\Drupal::messenger()->addError(\Drupal::translation()->formatPlural($results['failures'],'Failed to get available update data for one project.','Failed to get available update data for @count projects.'));
}
}
}
else{
\Drupal::messenger()->addError(t('An error occurred trying to get available update data.'),'error');
}
}
/**
* Implements hook_mail().
*
* Constructs the email notification message when the site is out of date.
*
* @param $key
* Unique key to indicate what message to build, always 'status_notify'.
* @param $message
* Reference to the message array being built.
* @param $params
* Array of parameters to indicate what kind of text to include in the message
* body. This is a keyed array of message type ('core' or 'contrib') as the
* keys, and the status reason constant (UPDATE_NOT_SECURE, etc) for the
$message['body'][]=t('See the available updates page for more information:',[],['langcode'=>$langcode])."\n".\Drupal::url('update.status',[],['absolute'=>TRUE,'language'=>$language]);
if(_update_manager_access()){
$message['body'][]=t('You can automatically install your missing updates using the Update manager:',[],['langcode'=>$langcode])."\n".\Drupal::url('update.report_update',[],['absolute'=>TRUE,'language'=>$language]);
$message['body'][]=t('Your site is currently configured to send these emails when any updates are available. To get notified only for security updates, @url.',['@url'=>$settings_url]);
}
else{
$message['body'][]=t('Your site is currently configured to send these emails only when security updates are available. To get notified for any available updates, @url.',['@url'=>$settings_url]);
}
}
/**
* Returns the appropriate message text when site is out of date or not secure.
*
* These error messages are shared by both update_requirements() for the
* site-wide status report at admin/reports/status and in the body of the
* notification email messages generated by update_cron().
*
* @param $msg_type
* String to indicate what kind of message to generate. Can be either 'core'
* or 'contrib'.
* @param $msg_reason
* Integer constant specifying why message is generated.
* @param $langcode
* (optional) A language code to use. Defaults to NULL.
*
* @return
* The properly translated error message for the given key.
$text=t('There is a security update available for your version of Drupal. To ensure the security of your server, you should update immediately!',[],['langcode'=>$langcode]);
}
else{
$text=t('There are security updates available for one or more of your modules or themes. To ensure the security of your server, you should update immediately!',[],['langcode'=>$langcode]);
}
break;
caseUPDATE_REVOKED:
if($msg_type=='core'){
$text=t('Your version of Drupal has been revoked and is no longer available for download. Upgrading is strongly recommended!',[],['langcode'=>$langcode]);
}
else{
$text=t('The installed version of at least one of your modules or themes has been revoked and is no longer available for download. Upgrading or disabling is strongly recommended!',[],['langcode'=>$langcode]);
}
break;
caseUPDATE_NOT_SUPPORTED:
if($msg_type=='core'){
$text=t('Your version of Drupal is no longer supported. Upgrading is strongly recommended!',[],['langcode'=>$langcode]);
}
else{
$text=t('The installed version of at least one of your modules or themes is no longer supported. Upgrading or disabling is strongly recommended. See the project homepage for more details.',[],['langcode'=>$langcode]);
}
break;
caseUPDATE_NOT_CURRENT:
if($msg_type=='core'){
$text=t('There are updates available for your version of Drupal. To ensure the proper functioning of your site, you should update as soon as possible.',[],['langcode'=>$langcode]);
}
else{
$text=t('There are updates available for one or more of your modules or themes. To ensure the proper functioning of your site, you should update as soon as possible.',[],['langcode'=>$langcode]);
}
break;
caseUPDATE_UNKNOWN:
caseUPDATE_NOT_CHECKED:
caseUPDATE_NOT_FETCHED:
caseUPDATE_FETCH_PENDING:
if($msg_type=='core'){
$text=t('There was a problem checking <a href=":update-report">available updates</a> for Drupal.',[':update-report'=>\Drupal::url('update.status')],['langcode'=>$langcode]);
}
else{
$text=t('There was a problem checking <a href=":update-report">available updates</a> for your modules or themes.',[':update-report'=>\Drupal::url('update.status')],['langcode'=>$langcode]);
}
break;
}
return$text;
}
/**
* Orders projects based on their status.
*
* Callback for uasort() within update_requirements().
*/
function_update_project_status_sort($a,$b){
// The status constants are numerically in the right order, so we can
// usually subtract the two to compare in the order we want. However,
// negative status values should be treated as if they are huge, since we
'no-core'=>t('Automatic updating of Drupal core is not supported. See the <a href=":upgrade-guide">upgrade guide</a> for information on how to update Drupal core manually.',[':upgrade-guide'=>'https://www.drupal.org/upgrade']),
];
}
// Parse all the .info.yml files and make sure at least one is compatible with
// this version of Drupal core. If one is compatible, then the project as a
// whole is considered compatible (since, for example, the project may ship
// with some out-of-date modules that are not necessary for its overall