Skip to content
Snippets Groups Projects
Commit 45cfddf8 authored by Lucas Hedding's avatar Lucas Hedding Committed by Lucas Hedding
Browse files

Issue #3093955 by heddn, ressa: Send email alert to administrator after automatic update

parent a32361fc
No related branches found
No related tags found
No related merge requests found
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
use Drupal\automatic_updates\ReadinessChecker\ReadinessCheckerManagerInterface; use Drupal\automatic_updates\ReadinessChecker\ReadinessCheckerManagerInterface;
use Drupal\automatic_updates\UpdateMetadata;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\update\UpdateManagerInterface; use Drupal\update\UpdateManagerInterface;
use Symfony\Component\Process\PhpExecutableFinder; use Symfony\Component\Process\PhpExecutableFinder;
...@@ -122,15 +123,17 @@ function automatic_updates_cron() { ...@@ -122,15 +123,17 @@ function automatic_updates_cron() {
if ($not_recommended_version && $projects['drupal']['existing_version'] !== $recommended_release['version']) { if ($not_recommended_version && $projects['drupal']['existing_version'] !== $recommended_release['version']) {
if ($config->get('enable_cron_security_updates')) { if ($config->get('enable_cron_security_updates')) {
if ($security_update) { if ($security_update) {
$metadata = new UpdateMetadata('drupal', 'core', \Drupal::VERSION, $recommended_release['version']);
/** @var \Drupal\automatic_updates\Services\UpdateInterface $updater */ /** @var \Drupal\automatic_updates\Services\UpdateInterface $updater */
$updater = \Drupal::service('automatic_updates.update'); $updater = \Drupal::service('automatic_updates.update');
$updater->update('drupal', 'core', \Drupal::VERSION, $recommended_release['version']); $updater->update($metadata);
} }
} }
else { else {
$metadata = new UpdateMetadata('drupal', 'core', \Drupal::VERSION, $recommended_release['version']);
/** @var \Drupal\automatic_updates\Services\UpdateInterface $updater */ /** @var \Drupal\automatic_updates\Services\UpdateInterface $updater */
$updater = \Drupal::service('automatic_updates.update'); $updater = \Drupal::service('automatic_updates.update');
$updater->update('drupal', 'core', \Drupal::VERSION, $recommended_release['version']); $updater->update($metadata);
} }
} }
} }
...@@ -148,6 +151,12 @@ function automatic_updates_theme(array $existing, $type, $theme, $path) { ...@@ -148,6 +151,12 @@ function automatic_updates_theme(array $existing, $type, $theme, $path) {
'messages' => [], 'messages' => [],
], ],
], ],
'automatic_updates_post_update' => [
'variables' => [
'success' => NULL,
'metadata' => NULL,
],
],
]; ];
} }
......
...@@ -46,6 +46,15 @@ services: ...@@ -46,6 +46,15 @@ services:
plugin.manager.database_update_handler: plugin.manager.database_update_handler:
class: Drupal\automatic_updates\DatabaseUpdateHandlerPluginManager class: Drupal\automatic_updates\DatabaseUpdateHandlerPluginManager
parent: default_plugin_manager parent: default_plugin_manager
automatic_updates.post_update_subscriber:
class: Drupal\automatic_updates\EventSubscriber\PostUpdateSubscriber
arguments:
- '@config.factory'
- '@plugin.manager.mail'
- '@language_manager'
- '@entity_type.manager'
tags:
- { name: event_subscriber }
automatic_updates.readiness_checker: automatic_updates.readiness_checker:
class: Drupal\automatic_updates\ReadinessChecker\ReadinessCheckerManager class: Drupal\automatic_updates\ReadinessChecker\ReadinessCheckerManager
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
namespace Drupal\automatic_updates\Controller; namespace Drupal\automatic_updates\Controller;
use Drupal\automatic_updates\Services\UpdateInterface; use Drupal\automatic_updates\Services\UpdateInterface;
use Drupal\automatic_updates\UpdateMetadata;
use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Messenger\MessengerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
...@@ -42,7 +43,8 @@ class InPlaceUpdateController extends ControllerBase { ...@@ -42,7 +43,8 @@ class InPlaceUpdateController extends ControllerBase {
* Builds the response. * Builds the response.
*/ */
public function update($project, $type, $from, $to) { public function update($project, $type, $from, $to) {
$updated = $this->updater->update($project, $type, $from, $to); $metadata = new UpdateMetadata($project, $type, $from, $to);
$updated = $this->updater->update($metadata);
$message_type = MessengerInterface::TYPE_STATUS; $message_type = MessengerInterface::TYPE_STATUS;
$message = $this->t('Update successful'); $message = $this->t('Update successful');
if (!$updated) { if (!$updated) {
......
<?php
namespace Drupal\automatic_updates\Event;
use Drupal\automatic_updates\UpdateMetadata;
use Symfony\Component\EventDispatcher\Event;
/**
* Defines the post update event.
*
* @see \Drupal\automatic_updates\Event\UpdateEvents
*/
class PostUpdateEvent extends Event {
/**
* The update metadata.
*
* @var \Drupal\automatic_updates\UpdateMetadata
*/
protected $updateMetadata;
/**
* The update success status.
*
* @var bool
*/
protected $success;
/**
* Constructs a new PostUpdateEvent.
*
* @param \Drupal\automatic_updates\UpdateMetadata $metadata
* The update metadata.
* @param bool $success
* TRUE if update succeeded, FALSE otherwise.
*/
public function __construct(UpdateMetadata $metadata, $success) {
$this->updateMetadata = $metadata;
$this->success = $success;
}
/**
* Get the update metadata.
*
* @return \Drupal\automatic_updates\UpdateMetadata
* The update metadata.
*/
public function getUpdateMetadata() {
return $this->updateMetadata;
}
/**
* Gets the update success status.
*
* @return bool
* TRUE if update succeeded, FALSE otherwise.
*/
public function success() {
return $this->success;
}
}
<?php
namespace Drupal\automatic_updates\Event;
/**
* Defines events for the automatic_updates module.
*/
final class UpdateEvents {
/**
* Name of the event fired after updating a site.
*
* @Event
*
* @see \Drupal\automatic_updates\Event\PostUpdateEvent
*/
const POST_UPDATE = 'automatic_updates.post_update';
}
<?php
namespace Drupal\automatic_updates\EventSubscriber;
use Drupal\automatic_updates\Event\PostUpdateEvent;
use Drupal\automatic_updates\Event\UpdateEvents;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Mail\MailManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Post update event subscriber.
*/
class PostUpdateSubscriber implements EventSubscriberInterface {
use StringTranslationTrait;
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* Mail manager.
*
* @var \Drupal\Core\Mail\MailManagerInterface
*/
protected $mailManager;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* Entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* PostUpdateSubscriber constructor.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Drupal\Core\Mail\MailManagerInterface $mail_manager
* The mail manager.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* Entity type manager.
*/
public function __construct(ConfigFactoryInterface $config_factory, MailManagerInterface $mail_manager, LanguageManagerInterface $language_manager, EntityTypeManagerInterface $entity_type_manager) {
$this->configFactory = $config_factory;
$this->mailManager = $mail_manager;
$this->languageManager = $language_manager;
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
return [
UpdateEvents::POST_UPDATE => ['onPostUpdate'],
];
}
/**
* Send notification on post update with success/failure.
*
* @param \Drupal\automatic_updates\Event\PostUpdateEvent $event
* The post update event.
*/
public function onPostUpdate(PostUpdateEvent $event) {
$notify_list = $this->configFactory->get('update.settings')->get('notification.emails');
if (!empty($notify_list)) {
$params['subject'] = $this->t('Automatic update of "@project" succeeded', ['@project' => $event->getUpdateMetadata()->getProjectName()]);
if (!$event->success()) {
$params['subject'] = $this->t('Automatic update of "@project" failed', ['@project' => $event->getUpdateMetadata()->getProjectName()]);
}
$params['body'] = [
'#theme' => 'automatic_updates_post_update',
'#success' => $event->success(),
'#metadata' => $event->getUpdateMetadata(),
];
$default_langcode = $this->languageManager->getDefaultLanguage()->getId();
$params['langcode'] = $default_langcode;
foreach ($notify_list as $to) {
$this->doSend($to, $params);
}
}
}
/**
* Composes and send the email message.
*
* @param string $to
* The email address where the message will be sent.
* @param array $params
* Parameters to build the email.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function doSend($to, array $params) {
$users = $this->entityTypeManager->getStorage('user')
->loadByProperties(['mail' => $to]);
foreach ($users as $user) {
$to_user = reset($users);
$params['langcode'] = $to_user->getPreferredLangcode();
$this->mailManager->mail('automatic_updates', 'post_update', $to, $params['langcode'], $params);
}
}
}
...@@ -2,8 +2,11 @@ ...@@ -2,8 +2,11 @@
namespace Drupal\automatic_updates\Services; namespace Drupal\automatic_updates\Services;
use Drupal\automatic_updates\Event\PostUpdateEvent;
use Drupal\automatic_updates\Event\UpdateEvents;
use Drupal\automatic_updates\ProjectInfoTrait; use Drupal\automatic_updates\ProjectInfoTrait;
use Drupal\automatic_updates\ReadinessChecker\ReadinessCheckerManagerInterface; use Drupal\automatic_updates\ReadinessChecker\ReadinessCheckerManagerInterface;
use Drupal\automatic_updates\UpdateMetadata;
use Drupal\Component\FileSystem\FileSystem; use Drupal\Component\FileSystem\FileSystem;
use Drupal\Core\Archiver\ArchiverInterface; use Drupal\Core\Archiver\ArchiverInterface;
use Drupal\Core\Archiver\ArchiverManager; use Drupal\Core\Archiver\ArchiverManager;
...@@ -128,7 +131,7 @@ class InPlaceUpdate implements UpdateInterface { ...@@ -128,7 +131,7 @@ class InPlaceUpdate implements UpdateInterface {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function update($project_name, $project_type, $from_version, $to_version) { public function update(UpdateMetadata $metadata) {
// Bail immediately on updates if error category checks fail. // Bail immediately on updates if error category checks fail.
/** @var \Drupal\automatic_updates\ReadinessChecker\ReadinessCheckerManagerInterface $readiness_check_manager */ /** @var \Drupal\automatic_updates\ReadinessChecker\ReadinessCheckerManagerInterface $readiness_check_manager */
$checker = \Drupal::service('automatic_updates.readiness_checker'); $checker = \Drupal::service('automatic_updates.readiness_checker');
...@@ -136,14 +139,14 @@ class InPlaceUpdate implements UpdateInterface { ...@@ -136,14 +139,14 @@ class InPlaceUpdate implements UpdateInterface {
return FALSE; return FALSE;
} }
$success = FALSE; $success = FALSE;
if ($project_name === 'drupal') { if ($metadata->getProjectName() === 'drupal') {
$project_root = $this->rootPath; $project_root = $this->rootPath;
} }
else { else {
$project_root = drupal_get_path($project_type, $project_name); $project_root = drupal_get_path($metadata->getProjectType(), $metadata->getProjectName());
} }
if ($archive = $this->getArchive($project_name, $from_version, $to_version)) { if ($archive = $this->getArchive($metadata)) {
$modified = $this->checkModifiedFiles($project_name, $project_type, $archive); $modified = $this->checkModifiedFiles($metadata, $archive);
if (!$modified && $this->backup($archive, $project_root)) { if (!$modified && $this->backup($archive, $project_root)) {
$this->logger->info('In place update has started.'); $this->logger->info('In place update has started.');
$success = $this->processUpdate($archive, $project_root); $success = $this->processUpdate($archive, $project_root);
...@@ -168,30 +171,33 @@ class InPlaceUpdate implements UpdateInterface { ...@@ -168,30 +171,33 @@ class InPlaceUpdate implements UpdateInterface {
} }
} }
} }
/** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
$event_dispatcher = \Drupal::service('event_dispatcher');
$event = new PostUpdateEvent($metadata, $success);
$event_dispatcher->dispatch(UpdateEvents::POST_UPDATE, $event);
return $success; return $success;
} }
/** /**
* Get an archive with the quasi-patch contents. * Get an archive with the quasi-patch contents.
* *
* @param string $project_name * @param \Drupal\automatic_updates\UpdateMetadata $metadata
* The project name. * The update metadata.
* @param string $from_version
* The current project version.
* @param string $to_version
* The desired next project version.
* *
* @return \Drupal\Core\Archiver\ArchiverInterface|null * @return \Drupal\Core\Archiver\ArchiverInterface|null
* The archive or NULL if download fails. * The archive or NULL if download fails.
*
* @throws \SodiumException
*/ */
protected function getArchive($project_name, $from_version, $to_version) { protected function getArchive(UpdateMetadata $metadata) {
$quasi_patch = $this->getQuasiPatchFileName($project_name, $from_version, $to_version); $quasi_patch = $this->getQuasiPatchFileName($metadata);
$url = $this->buildUrl($project_name, $quasi_patch); $url = $this->buildUrl($metadata->getProjectName(), $quasi_patch);
$temp_directory = FileSystem::getOsTemporaryDirectory() . DIRECTORY_SEPARATOR; $temp_directory = FileSystem::getOsTemporaryDirectory() . DIRECTORY_SEPARATOR;
$destination = $this->fileSystem->getDestinationFilename($temp_directory . $quasi_patch, FileSystemInterface::EXISTS_REPLACE); $destination = $this->fileSystem->getDestinationFilename($temp_directory . $quasi_patch, FileSystemInterface::EXISTS_REPLACE);
$this->doGetResource($url, $destination); $this->doGetResource($url, $destination);
$csig_file = $quasi_patch . '.csig'; $csig_file = $quasi_patch . '.csig';
$csig_url = $this->buildUrl($project_name, $csig_file); $csig_url = $this->buildUrl($metadata->getProjectName(), $csig_file);
$csig_destination = $this->fileSystem->getDestinationFilename(FileSystem::getOsTemporaryDirectory() . DIRECTORY_SEPARATOR . $csig_file, FileSystemInterface::EXISTS_REPLACE); $csig_destination = $this->fileSystem->getDestinationFilename(FileSystem::getOsTemporaryDirectory() . DIRECTORY_SEPARATOR . $csig_file, FileSystemInterface::EXISTS_REPLACE);
$this->doGetResource($csig_url, $csig_destination); $this->doGetResource($csig_url, $csig_destination);
$csig = file_get_contents($csig_destination); $csig = file_get_contents($csig_destination);
...@@ -202,25 +208,23 @@ class InPlaceUpdate implements UpdateInterface { ...@@ -202,25 +208,23 @@ class InPlaceUpdate implements UpdateInterface {
/** /**
* Check if files are modified before applying updates. * Check if files are modified before applying updates.
* *
* @param string $project_name * @param \Drupal\automatic_updates\UpdateMetadata $metadata
* The project name. * The update metadata.
* @param string $project_type
* The project type.
* @param \Drupal\Core\Archiver\ArchiverInterface $archive * @param \Drupal\Core\Archiver\ArchiverInterface $archive
* The archive. * The archive.
* *
* @return bool * @return bool
* Return TRUE if modified files exist, FALSE otherwise. * Return TRUE if modified files exist, FALSE otherwise.
*/ */
protected function checkModifiedFiles($project_name, $project_type, ArchiverInterface $archive) { protected function checkModifiedFiles(UpdateMetadata $metadata, ArchiverInterface $archive) {
if ($project_type === 'core') { if ($metadata->getProjectType() === 'core') {
$project_type = 'module'; $metadata->setProjectType('module');
} }
$extensions = $this->getInfos($project_type); $extensions = $this->getInfos($metadata->getProjectType());
/** @var \Drupal\automatic_updates\Services\ModifiedFilesInterface $modified_files */ /** @var \Drupal\automatic_updates\Services\ModifiedFilesInterface $modified_files */
$modified_files = \Drupal::service('automatic_updates.modified_files'); $modified_files = \Drupal::service('automatic_updates.modified_files');
try { try {
$files = iterator_to_array($modified_files->getModifiedFiles([$extensions[$project_name]])); $files = iterator_to_array($modified_files->getModifiedFiles([$extensions[$metadata->getProjectName()]]));
} }
catch (RequestException $exception) { catch (RequestException $exception) {
// While not strictly true that there are modified files, we can't be sure // While not strictly true that there are modified files, we can't be sure
...@@ -525,18 +529,14 @@ class InPlaceUpdate implements UpdateInterface { ...@@ -525,18 +529,14 @@ class InPlaceUpdate implements UpdateInterface {
/** /**
* Get the quasi-patch file name. * Get the quasi-patch file name.
* *
* @param string $project_name * @param \Drupal\automatic_updates\UpdateMetadata $metadata
* The project name. * The update metadata.
* @param string $from_version
* The current project version.
* @param string $to_version
* The desired next project version.
* *
* @return string * @return string
* The quasi-patch file name. * The quasi-patch file name.
*/ */
protected function getQuasiPatchFileName($project_name, $from_version, $to_version) { protected function getQuasiPatchFileName(UpdateMetadata $metadata) {
return "$project_name-$from_version-to-$to_version.zip"; return "{$metadata->getProjectName()}-{$metadata->getFromVersion()}-to-{$metadata->getToVersion()}.zip";
} }
/** /**
......
...@@ -157,11 +157,11 @@ class Notify implements NotifyInterface { ...@@ -157,11 +157,11 @@ class Notify implements NotifyInterface {
protected function doSend($to, array $params) { protected function doSend($to, array $params) {
$users = $this->entityTypeManager->getStorage('user') $users = $this->entityTypeManager->getStorage('user')
->loadByProperties(['mail' => $to]); ->loadByProperties(['mail' => $to]);
if ($users) { foreach ($users as $user) {
$to_user = reset($users); $to_user = reset($users);
$params['langcode'] = $to_user->getPreferredLangcode(); $params['langcode'] = $to_user->getPreferredLangcode();
$this->mailManager->mail('automatic_updates', 'notify', $to, $params['langcode'], $params);
} }
$this->mailManager->mail('automatic_updates', 'notify', $to, $params['langcode'], $params);
} }
} }
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
namespace Drupal\automatic_updates\Services; namespace Drupal\automatic_updates\Services;
use Drupal\automatic_updates\UpdateMetadata;
/** /**
* Interface UpdateInterface. * Interface UpdateInterface.
*/ */
...@@ -10,18 +12,12 @@ interface UpdateInterface { ...@@ -10,18 +12,12 @@ interface UpdateInterface {
/** /**
* Update a project to the next release. * Update a project to the next release.
* *
* @param string $project_name * @param \Drupal\automatic_updates\UpdateMetadata $metadata
* The project name. * The update metadata.
* @param string $project_type
* The project type.
* @param string $from_version
* The current project version.
* @param string $to_version
* The desired next project version.
* *
* @return bool * @return bool
* TRUE if project was successfully updated, FALSE otherwise. * TRUE if project was successfully updated, FALSE otherwise.
*/ */
public function update($project_name, $project_type, $from_version, $to_version); public function update(UpdateMetadata $metadata);
} }
<?php
namespace Drupal\automatic_updates;
/**
* Transfer object to encapsulate the details for an update.
*/
final class UpdateMetadata {
/**
* The project name.
*
* @var string
*/
protected $projectName;
/**
* The project type.
*
* @var string
*/
protected $projectType;
/**
* The current project version.
*
* @var string
*/
protected $fromVersion;
/**
* The desired next project version.
*
* @var string
*/
protected $toVersion;
/**
* UpdateMetadata constructor.
*
* @param string $project_name
* The project name.
* @param string $project_type
* The project type.
* @param string $from_version
* The current project version.
* @param string $to_version
* The desired next project version.
*/
public function __construct($project_name, $project_type, $from_version, $to_version) {
$this->projectName = $project_name;
$this->projectType = $project_type;
$this->fromVersion = $from_version;
$this->toVersion = $to_version;
}
/**
* Get project name.
*
* @return string
* The project nam.
*/
public function getProjectName() {
return $this->projectName;
}
/**
* Set the project name.
*
* @param string $projectName
* The project name.
*
* @return \Drupal\automatic_updates\UpdateMetadata
* The update metadata.
*/
public function setProjectName($projectName) {
$this->projectName = $projectName;
return $this;
}
/**
* Get the project type.
*
* @return string
* The project type.
*/
public function getProjectType() {
return $this->projectType;
}
/**
* Set the project type.
*
* @param string $projectType
* The project type.
*
* @return \Drupal\automatic_updates\UpdateMetadata
* The update metadata.
*/
public function setProjectType($projectType) {
$this->projectType = $projectType;
return $this;
}
/**
* Get the current project version.
*
* @return string
* The current project version.
*/
public function getFromVersion() {
return $this->fromVersion;
}
/**
* Set the current project version.
*
* @param string $fromVersion
* The current project version.
*
* @return \Drupal\automatic_updates\UpdateMetadata
* The update metadata.
*/
public function setFromVersion($fromVersion) {
$this->fromVersion = $fromVersion;
return $this;
}
/**
* Get the desired next project version.
*
* @return string
* The desired next project version.
*/
public function getToVersion() {
return $this->toVersion;
}
/**
* Set the desired next project version.
*
* @param string $toVersion
* The desired next project version.
*
* @return \Drupal\automatic_updates\UpdateMetadata
* The update metadata.
*/
public function setToVersion($toVersion) {
$this->toVersion = $toVersion;
return $this;
}
}
{#
/**
* @file
* Template for the post update email notification.
*
* Available variables:
* - success: The update success status
* - metadata: The update metadata
*
* @ingroup themeable
*/
#}
<p>
{% if success %}
{{ 'The project "@project" was updated from "@from_version" to "@to_version" with success.'|t({
'@project': metadata.getProjectName,
'@from_version': metadata.getFromVersion,
'@to_version': metadata.getToVersion,
}) }}
{% else %}
{{ 'The project "@project" was updated from "@from_version" to "@to_version" with failures.'|t({
'@project': metadata.getProjectName,
'@from_version': metadata.getFromVersion,
'@to_version': metadata.getToVersion,
}) }}
{% endif %}
</p>
<p>
{% set status_report = path('system.status') %}
{% trans %}
See the <a href="{{ status_report }}">site status report page</a> and any logs for more information.
{% endtrans %}
</p>
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
namespace Drupal\test_automatic_updates\Controller; namespace Drupal\test_automatic_updates\Controller;
use Drupal\automatic_updates\Services\UpdateInterface; use Drupal\automatic_updates\Services\UpdateInterface;
use Drupal\automatic_updates\UpdateMetadata;
use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
...@@ -41,7 +42,8 @@ class InPlaceUpdateController extends ControllerBase { ...@@ -41,7 +42,8 @@ class InPlaceUpdateController extends ControllerBase {
* Builds the response. * Builds the response.
*/ */
public function update($project, $type, $from, $to) { public function update($project, $type, $from, $to) {
$updated = $this->updater->update($project, $type, $from, $to); $metadata = new UpdateMetadata($project, $type, $from, $to);
$updated = $this->updater->update($metadata);
return [ return [
'#markup' => $updated ? $this->t('Update successful') : $this->t('Update Failed'), '#markup' => $updated ? $this->t('Update successful') : $this->t('Update Failed'),
]; ];
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
namespace Drupal\Tests\automatic_updates\Functional; namespace Drupal\Tests\automatic_updates\Functional;
use Drupal\automatic_updates\Event\PostUpdateEvent;
use Drupal\automatic_updates\UpdateMetadata;
use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Test\AssertMailTrait; use Drupal\Core\Test\AssertMailTrait;
use Drupal\Core\Url; use Drupal\Core\Url;
...@@ -60,9 +62,9 @@ class NotifyTest extends BrowserTestBase { ...@@ -60,9 +62,9 @@ class NotifyTest extends BrowserTestBase {
} }
/** /**
* Tests sending email notifications. * Tests sending PSA email notifications.
*/ */
public function testSendMail() { public function testPsaMail() {
// Test PSAs on admin pages. // Test PSAs on admin pages.
$this->drupalGet(Url::fromRoute('system.admin')); $this->drupalGet(Url::fromRoute('system.admin'));
$this->assertSession()->pageTextContains('Critical Release - SA-2019-02-19'); $this->assertSession()->pageTextContains('Critical Release - SA-2019-02-19');
...@@ -84,4 +86,27 @@ class NotifyTest extends BrowserTestBase { ...@@ -84,4 +86,27 @@ class NotifyTest extends BrowserTestBase {
$this->assertCount(0, $this->getMails()); $this->assertCount(0, $this->getMails());
} }
/**
* Tests sending post update email notifications.
*/
public function testPostUpdateMail() {
// Success email.
$metadata = new UpdateMetadata('drupal', 'core', '8.7.0', '8.8.0');
$post_update = new PostUpdateEvent($metadata, TRUE);
$notify = $this->container->get('automatic_updates.post_update_subscriber');
$notify->onPostUpdate($post_update);
$this->assertCount(1, $this->getMails());
$this->assertMailString('subject', 'Automatic update of "drupal" succeeded', 1);
$this->assertMailString('body', 'The project "drupal" was updated from "8.7.0" to "8.8.0" with success.', 1);
// Failure email.
$this->container->get('state')->set('system.test_mail_collector', []);
$post_update = new PostUpdateEvent($metadata, FALSE);
$notify = $this->container->get('automatic_updates.post_update_subscriber');
$notify->onPostUpdate($post_update);
$this->assertCount(1, $this->getMails());
$this->assertMailString('subject', 'Automatic update of "drupal" failed', 1);
$this->assertMailString('body', 'The project "drupal" was updated from "8.7.0" to "8.8.0" with failures.', 1);
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment