diff --git a/app/code/Magento/AdminNotification/Controller/Adminhtml/Notification/AjaxMarkAsRead.php b/app/code/Magento/AdminNotification/Controller/Adminhtml/Notification/AjaxMarkAsRead.php
index 31a129d57ab90..da797fe12e75a 100644
--- a/app/code/Magento/AdminNotification/Controller/Adminhtml/Notification/AjaxMarkAsRead.php
+++ b/app/code/Magento/AdminNotification/Controller/Adminhtml/Notification/AjaxMarkAsRead.php
@@ -6,12 +6,35 @@
*/
namespace Magento\AdminNotification\Controller\Adminhtml\Notification;
+use Magento\Backend\App\Action;
+use Magento\Framework\Controller\ResultFactory;
+
class AjaxMarkAsRead extends \Magento\AdminNotification\Controller\Adminhtml\Notification
{
+ /**
+ * @var \Magento\AdminNotification\Model\NotificationService
+ */
+ private $notificationService;
+
+ /**
+ * @param Action\Context $context
+ * @param \Magento\AdminNotification\Model\NotificationService|null $notificationService
+ * @throws \RuntimeException
+ */
+ public function __construct(
+ Action\Context $context,
+ \Magento\AdminNotification\Model\NotificationService $notificationService = null
+ ) {
+ parent::__construct($context);
+ $this->notificationService = $notificationService?: \Magento\Framework\App\ObjectManager::getInstance()
+ ->get(\Magento\AdminNotification\Model\NotificationService::class);
+ }
+
/**
* Mark notification as read (AJAX action)
*
- * @return void
+ * @return \Magento\Framework\Controller\Result\Json|void
+ * @throws \InvalidArgumentException
*/
public function execute()
{
@@ -21,17 +44,15 @@ public function execute()
$notificationId = (int)$this->getRequest()->getPost('id');
$responseData = [];
try {
- $this->_objectManager->create(
- \Magento\AdminNotification\Model\NotificationService::class
- )->markAsRead(
- $notificationId
- );
+ $this->notificationService->markAsRead($notificationId);
$responseData['success'] = true;
} catch (\Exception $e) {
$responseData['success'] = false;
}
- $this->getResponse()->representJson(
- $this->_objectManager->create(\Magento\Framework\Json\Helper\Data::class)->jsonEncode($responseData)
- );
+
+ /** @var \Magento\Framework\Controller\Result\Json $resultJson */
+ $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON);
+ $resultJson->setData($responseData);
+ return $resultJson;
}
}
diff --git a/app/code/Magento/AdminNotification/composer.json b/app/code/Magento/AdminNotification/composer.json
index afb820a2e6c93..227837558a8b3 100644
--- a/app/code/Magento/AdminNotification/composer.json
+++ b/app/code/Magento/AdminNotification/composer.json
@@ -3,15 +3,15 @@
"description": "N/A",
"require": {
"php": "7.0.2|7.0.4|~7.0.6|~7.1.0",
- "magento/module-store": "100.2.*",
- "magento/module-backend": "100.2.*",
- "magento/module-media-storage": "100.2.*",
- "magento/framework": "100.2.*",
- "magento/module-ui": "100.2.*",
+ "magento/module-store": "100.3.*",
+ "magento/module-backend": "100.3.*",
+ "magento/module-media-storage": "100.3.*",
+ "magento/framework": "100.3.*",
+ "magento/module-ui": "100.3.*",
"lib-libxml": "*"
},
"type": "magento2-module",
- "version": "100.2.0-dev",
+ "version": "100.3.0-dev",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/AdminNotification/i18n/en_US.csv b/app/code/Magento/AdminNotification/i18n/en_US.csv
index 1afb8104bfef6..16c5abb9db0d2 100644
--- a/app/code/Magento/AdminNotification/i18n/en_US.csv
+++ b/app/code/Magento/AdminNotification/i18n/en_US.csv
@@ -1,13 +1,13 @@
"Read Details","Read Details"
"Mark as Read","Mark as Read"
"Are you sure?","Are you sure?"
-"Remove","Remove"
+Remove,Remove
"Messages Inbox","Messages Inbox"
"You have %1 new system messages","You have %1 new system messages"
"You have %1 new system message","You have %1 new system message"
"Incoming Message","Incoming Message"
-"close","close"
-"Notifications","Notifications"
+close,close
+Notifications,Notifications
"The message has been marked as Read.","The message has been marked as Read."
"We couldn't mark the notification as Read because of an error.","We couldn't mark the notification as Read because of an error."
"Please select messages.","Please select messages."
@@ -20,10 +20,10 @@
"6 Hours","6 Hours"
"12 Hours","12 Hours"
"24 Hours","24 Hours"
-"critical","critical"
-"major","major"
-"minor","minor"
-"notice","notice"
+critical,critical
+major,major
+minor,minor
+notice,notice
"Wrong message type","Wrong message type"
"Wrong notification ID specified.","Wrong notification ID specified."
"{{base_url}} is not recommended to use in a production environment to declare the Base Unsecure URL / Base Secure URL. We highly recommend changing this value in your Magento configuration.","{{base_url}} is not recommended to use in a production environment to declare the Base Unsecure URL / Base Secure URL. We highly recommend changing this value in your Magento configuration."
@@ -32,12 +32,11 @@
"We were unable to synchronize one or more media files. Please refer to the log file for details.","We were unable to synchronize one or more media files. Please refer to the log file for details."
"Synchronization of media storages has been completed.","Synchronization of media storages has been completed."
"Your web server is set up incorrectly and allows unauthorized access to sensitive files. Please contact your hosting provider.","Your web server is set up incorrectly and allows unauthorized access to sensitive files. Please contact your hosting provider."
-"Close popup","Close popup"
-"Close","Close"
"System Messages:","System Messages:"
"Critical System Messages","Critical System Messages"
"Major System Messages","Major System Messages"
"System messages","System messages"
+Close,Close
"See All (","See All ("
" unread)"," unread)"
"Show Toolbar","Show Toolbar"
@@ -45,7 +44,7 @@
"Use HTTPS to Get Feed","Use HTTPS to Get Feed"
"Update Frequency","Update Frequency"
"Last Update","Last Update"
-"Severity","Severity"
+Severity,Severity
"Date Added","Date Added"
-"Message","Message"
-"Actions","Actions"
+Message,Message
+Actions,Actions
diff --git a/app/code/Magento/AdvancedPricingImportExport/composer.json b/app/code/Magento/AdvancedPricingImportExport/composer.json
index 228464ecd6304..acc3e3ead715a 100644
--- a/app/code/Magento/AdvancedPricingImportExport/composer.json
+++ b/app/code/Magento/AdvancedPricingImportExport/composer.json
@@ -3,17 +3,17 @@
"description": "N/A",
"require": {
"php": "7.0.2|7.0.4|~7.0.6|~7.1.0",
- "magento/module-catalog": "101.1.*",
- "magento/module-catalog-inventory": "100.2.*",
- "magento/module-eav": "100.2.*",
- "magento/module-import-export": "100.2.*",
- "magento/module-catalog-import-export": "100.2.*",
- "magento/module-customer": "100.2.*",
- "magento/module-store": "100.2.*",
- "magento/framework": "100.2.*"
+ "magento/module-catalog": "101.2.*",
+ "magento/module-catalog-inventory": "100.3.*",
+ "magento/module-eav": "100.3.*",
+ "magento/module-import-export": "100.3.*",
+ "magento/module-catalog-import-export": "100.3.*",
+ "magento/module-customer": "100.3.*",
+ "magento/module-store": "100.3.*",
+ "magento/framework": "100.3.*"
},
"type": "magento2-module",
- "version": "100.2.0-dev",
+ "version": "100.3.0-dev",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/AdvancedPricingImportExport/i18n/en_US.csv b/app/code/Magento/AdvancedPricingImportExport/i18n/en_US.csv
index 56b3d249c4123..54afa107ef377 100644
--- a/app/code/Magento/AdvancedPricingImportExport/i18n/en_US.csv
+++ b/app/code/Magento/AdvancedPricingImportExport/i18n/en_US.csv
@@ -1,4 +1,4 @@
"Please correct the data sent.","Please correct the data sent."
-"Entity type model \'%1\' is not found","Entity type model \'%1\' is not found"
+"Entity type model '%1' is not found","Entity type model '%1' is not found"
"Entity type model must be an instance of \Magento\CatalogImportExport\Model\Export\Product\Type\AbstractType","Entity type model must be an instance of \Magento\CatalogImportExport\Model\Export\Product\Type\AbstractType"
"There are no product types available for export","There are no product types available for export"
diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php b/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php
index 7f0aade798e18..1b0e5c92420de 100644
--- a/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php
+++ b/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php
@@ -5,6 +5,7 @@
*/
namespace Magento\Analytics\Controller\Adminhtml\Reports;
+use Magento\Analytics\Model\Exception\State\SubscriptionUpdateException;
use Magento\Analytics\Model\ReportUrlProvider;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
@@ -55,6 +56,9 @@ public function execute()
$resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
try {
$resultRedirect->setUrl($this->reportUrlProvider->getUrl());
+ } catch (SubscriptionUpdateException $e) {
+ $this->getMessageManager()->addNoticeMessage($e->getMessage());
+ $resultRedirect->setPath('adminhtml');
} catch (LocalizedException $e) {
$this->getMessageManager()->addExceptionMessage($e, $e->getMessage());
$resultRedirect->setPath('adminhtml');
diff --git a/app/code/Magento/Analytics/Cron/Update.php b/app/code/Magento/Analytics/Cron/Update.php
index 36e6c3e59e5c7..9062a7bac7551 100644
--- a/app/code/Magento/Analytics/Cron/Update.php
+++ b/app/code/Magento/Analytics/Cron/Update.php
@@ -5,14 +5,14 @@
*/
namespace Magento\Analytics\Cron;
+use Magento\Analytics\Model\AnalyticsToken;
+use Magento\Analytics\Model\Config\Backend\Baseurl\SubscriptionUpdateHandler;
use Magento\Analytics\Model\Connector;
-use Magento\Analytics\Model\Plugin\BaseUrlConfigPlugin;
use Magento\Framework\FlagManager;
use Magento\Framework\App\Config\ReinitableConfigInterface;
use Magento\Framework\App\Config\Storage\WriterInterface;
/**
- * Class Update
* Executes by cron schedule in case base url was changed
*/
class Update
@@ -28,8 +28,6 @@ class Update
private $configWriter;
/**
- * Reinitable Config Model.
- *
* @var ReinitableConfigInterface
*/
private $reinitableConfig;
@@ -40,22 +38,29 @@ class Update
private $flagManager;
/**
- * Update constructor.
+ * @var AnalyticsToken
+ */
+ private $analyticsToken;
+
+ /**
* @param Connector $connector
* @param WriterInterface $configWriter
* @param ReinitableConfigInterface $reinitableConfig
* @param FlagManager $flagManager
+ * @param AnalyticsToken $analyticsToken
*/
public function __construct(
Connector $connector,
WriterInterface $configWriter,
ReinitableConfigInterface $reinitableConfig,
- FlagManager $flagManager
+ FlagManager $flagManager,
+ AnalyticsToken $analyticsToken
) {
$this->connector = $connector;
$this->configWriter = $configWriter;
$this->reinitableConfig = $reinitableConfig;
$this->flagManager = $flagManager;
+ $this->analyticsToken = $analyticsToken;
}
/**
@@ -65,13 +70,23 @@ public function __construct(
*/
public function execute()
{
- $updateResult = $this->connector->execute('update');
- if ($updateResult === false) {
- return false;
+ $result = false;
+ $attemptsCount = $this->flagManager
+ ->getFlagData(SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE);
+
+ if ($attemptsCount) {
+ $attemptsCount -= 1;
+ $result = $this->connector->execute('update');
+ }
+
+ if ($result || ($attemptsCount <= 0) || (!$this->analyticsToken->isTokenExist())) {
+ $this->flagManager
+ ->deleteFlag(SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE);
+ $this->flagManager->deleteFlag(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE);
+ $this->configWriter->delete(SubscriptionUpdateHandler::UPDATE_CRON_STRING_PATH);
+ $this->reinitableConfig->reinit();
}
- $this->configWriter->delete(BaseUrlConfigPlugin::UPDATE_CRON_STRING_PATH);
- $this->flagManager->deleteFlag(BaseUrlConfigPlugin::OLD_BASE_URL_FLAG_CODE);
- $this->reinitableConfig->reinit();
- return true;
+
+ return $result;
}
}
diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php b/app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php
new file mode 100644
index 0000000000000..6e6f008d49f7e
--- /dev/null
+++ b/app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php
@@ -0,0 +1,107 @@
+analyticsToken = $analyticsToken;
+ $this->flagManager = $flagManager;
+ $this->reinitableConfig = $reinitableConfig;
+ $this->configWriter = $configWriter;
+ }
+
+ /**
+ * Activate process of subscription update handling.
+ *
+ * @param string $url
+ * @return bool
+ */
+ public function processUrlUpdate(string $url)
+ {
+ if ($this->analyticsToken->isTokenExist()) {
+ if (!$this->flagManager->getFlagData(self::PREVIOUS_BASE_URL_FLAG_CODE)) {
+ $this->flagManager->saveFlag(self::PREVIOUS_BASE_URL_FLAG_CODE, $url);
+ }
+
+ $this->flagManager
+ ->saveFlag(self::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE, $this->attemptsInitValue);
+ $this->configWriter->save(self::UPDATE_CRON_STRING_PATH, $this->cronExpression);
+ $this->reinitableConfig->reinit();
+ }
+
+ return true;
+ }
+}
diff --git a/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php b/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php
index 177ee64c82c5b..f1a8ea6460f9d 100644
--- a/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php
+++ b/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php
@@ -6,8 +6,8 @@
namespace Magento\Analytics\Model\Connector;
use Magento\Analytics\Model\AnalyticsToken;
+use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\HTTP\ZendClient;
-use Magento\Config\Model\Config;
use Psr\Log\LoggerInterface;
use Magento\Store\Model\Store;
use Magento\Analytics\Model\Connector\Http\ResponseResolver;
@@ -33,7 +33,7 @@ class NotifyDataChangedCommand implements CommandInterface
private $httpClient;
/**
- * @var Config
+ * @var ScopeConfigInterface
*/
private $config;
@@ -51,14 +51,14 @@ class NotifyDataChangedCommand implements CommandInterface
* NotifyDataChangedCommand constructor.
* @param AnalyticsToken $analyticsToken
* @param Http\ClientInterface $httpClient
- * @param Config $config
+ * @param ScopeConfigInterface $config
* @param ResponseResolver $responseResolver
* @param LoggerInterface $logger
*/
public function __construct(
AnalyticsToken $analyticsToken,
Http\ClientInterface $httpClient,
- Config $config,
+ ScopeConfigInterface $config,
ResponseResolver $responseResolver,
LoggerInterface $logger
) {
@@ -80,16 +80,14 @@ public function execute()
if ($this->analyticsToken->isTokenExist()) {
$response = $this->httpClient->request(
ZendClient::POST,
- $this->config->getConfigDataValue($this->notifyDataChangedUrlPath),
+ $this->config->getValue($this->notifyDataChangedUrlPath),
[
"access-token" => $this->analyticsToken->getToken(),
- "url" => $this->config->getConfigDataValue(
- Store::XML_PATH_SECURE_BASE_URL
- ),
+ "url" => $this->config->getValue(Store::XML_PATH_SECURE_BASE_URL),
]
);
$result = $this->responseResolver->getResult($response);
}
- return $result;
+ return (bool)$result;
}
}
diff --git a/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php b/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php
index 367b46de17c4b..a1f23637e04b1 100644
--- a/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php
+++ b/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php
@@ -8,7 +8,7 @@
use Magento\Analytics\Model\AnalyticsToken;
use Magento\Analytics\Model\Connector\Http\ResponseResolver;
use Magento\Analytics\Model\IntegrationManager;
-use Magento\Config\Model\Config;
+use Magento\Framework\App\Config\ScopeConfigInterface;
use Psr\Log\LoggerInterface;
use Magento\Framework\HTTP\ZendClient;
use Magento\Store\Model\Store;
@@ -36,7 +36,7 @@ class SignUpCommand implements CommandInterface
private $integrationManager;
/**
- * @var Config
+ * @var ScopeConfigInterface
*/
private $config;
@@ -60,7 +60,7 @@ class SignUpCommand implements CommandInterface
*
* @param AnalyticsToken $analyticsToken
* @param IntegrationManager $integrationManager
- * @param Config $config
+ * @param ScopeConfigInterface $config
* @param Http\ClientInterface $httpClient
* @param LoggerInterface $logger
* @param ResponseResolver $responseResolver
@@ -68,7 +68,7 @@ class SignUpCommand implements CommandInterface
public function __construct(
AnalyticsToken $analyticsToken,
IntegrationManager $integrationManager,
- Config $config,
+ ScopeConfigInterface $config,
Http\ClientInterface $httpClient,
LoggerInterface $logger,
ResponseResolver $responseResolver
@@ -101,12 +101,10 @@ public function execute()
$this->integrationManager->activateIntegration();
$response = $this->httpClient->request(
ZendClient::POST,
- $this->config->getConfigDataValue($this->signUpUrlPath),
+ $this->config->getValue($this->signUpUrlPath),
[
"token" => $integrationToken->getData('token'),
- "url" => $this->config->getConfigDataValue(
- Store::XML_PATH_SECURE_BASE_URL
- )
+ "url" => $this->config->getValue(Store::XML_PATH_SECURE_BASE_URL),
]
);
@@ -121,6 +119,6 @@ public function execute()
}
}
- return $result;
+ return (bool)$result;
}
}
diff --git a/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php b/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php
index a2d64a98e0409..8f05f1107e87e 100644
--- a/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php
+++ b/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php
@@ -6,9 +6,9 @@
namespace Magento\Analytics\Model\Connector;
use Magento\Analytics\Model\AnalyticsToken;
+use Magento\Analytics\Model\Config\Backend\Baseurl\SubscriptionUpdateHandler;
use Magento\Analytics\Model\Connector\Http\ResponseResolver;
-use Magento\Analytics\Model\Plugin\BaseUrlConfigPlugin;
-use Magento\Config\Model\Config;
+use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\FlagManager;
use Magento\Framework\HTTP\ZendClient;
use Magento\Store\Model\Store;
@@ -36,7 +36,7 @@ class UpdateCommand implements CommandInterface
private $httpClient;
/**
- * @var Config
+ * @var ScopeConfigInterface
*/
private $config;
@@ -58,7 +58,7 @@ class UpdateCommand implements CommandInterface
/**
* @param AnalyticsToken $analyticsToken
* @param Http\ClientInterface $httpClient
- * @param Config $config
+ * @param ScopeConfigInterface $config
* @param LoggerInterface $logger
* @param FlagManager $flagManager
* @param ResponseResolver $responseResolver
@@ -66,7 +66,7 @@ class UpdateCommand implements CommandInterface
public function __construct(
AnalyticsToken $analyticsToken,
Http\ClientInterface $httpClient,
- Config $config,
+ ScopeConfigInterface $config,
LoggerInterface $logger,
FlagManager $flagManager,
ResponseResolver $responseResolver
@@ -90,12 +90,11 @@ public function execute()
if ($this->analyticsToken->isTokenExist()) {
$response = $this->httpClient->request(
ZendClient::PUT,
- $this->config->getConfigDataValue($this->updateUrlPath),
+ $this->config->getValue($this->updateUrlPath),
[
- "url" => $this->flagManager->getFlagData(BaseUrlConfigPlugin::OLD_BASE_URL_FLAG_CODE),
- "new-url" => $this->config->getConfigDataValue(
- Store::XML_PATH_SECURE_BASE_URL
- ),
+ "url" => $this->flagManager
+ ->getFlagData(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE),
+ "new-url" => $this->config->getValue(Store::XML_PATH_SECURE_BASE_URL),
"access-token" => $this->analyticsToken->getToken(),
]
);
@@ -110,6 +109,6 @@ public function execute()
}
}
- return $result;
+ return (bool)$result;
}
}
diff --git a/app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php b/app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php
new file mode 100644
index 0000000000000..5d127037afea9
--- /dev/null
+++ b/app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php
@@ -0,0 +1,17 @@
+flagManager = $flagManager;
- $this->subscriptionStatusProvider = $subscriptionStatusProvider;
- $this->configWriter = $configWriter;
+ $this->subscriptionUpdateHandler = $subscriptionUpdateHandler;
}
/**
- * Sets update analytics cron job if base url was changed.
+ * Add additional handling after config value was saved.
*
- * @param \Magento\Config\Model\Config\Backend\Baseurl $subject
- * @param \Magento\Config\Model\Config\Backend\Baseurl $result
- * @return \Magento\Config\Model\Config\Backend\Baseurl
+ * @param Value $subject
+ * @param Value $result
+ * @return Value
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function afterAfterSave(
- \Magento\Config\Model\Config\Backend\Baseurl $subject,
- \Magento\Config\Model\Config\Backend\Baseurl $result
+ Value $subject,
+ Value $result
) {
- if (!$result->isValueChanged()) {
- return $result;
- }
-
if ($this->isPluginApplicable($result)) {
- $this->flagManager->saveFlag(static::OLD_BASE_URL_FLAG_CODE, $result->getOldValue());
- $this->configWriter->save(self::UPDATE_CRON_STRING_PATH, $this->cronExpression);
+ $this->subscriptionUpdateHandler->processUrlUpdate($result->getOldValue());
}
return $result;
}
/**
- * @param \Magento\Config\Model\Config\Backend\Baseurl $result
- *
+ * @param Value $result
* @return bool
*/
- private function isPluginApplicable(\Magento\Config\Model\Config\Backend\Baseurl $result)
+ private function isPluginApplicable(Value $result)
{
- return $result->getData('path') === \Magento\Store\Model\Store::XML_PATH_SECURE_BASE_URL
- && $this->subscriptionStatusProvider->getStatus() === SubscriptionStatusProvider::ENABLED;
+ return $result->isValueChanged()
+ && ($result->getPath() === Store::XML_PATH_SECURE_BASE_URL)
+ && ($result->getScope() === ScopeConfigInterface::SCOPE_TYPE_DEFAULT);
}
}
diff --git a/app/code/Magento/Analytics/Model/ReportUrlProvider.php b/app/code/Magento/Analytics/Model/ReportUrlProvider.php
index b72374f4d9f62..e7fdf6f9e8132 100644
--- a/app/code/Magento/Analytics/Model/ReportUrlProvider.php
+++ b/app/code/Magento/Analytics/Model/ReportUrlProvider.php
@@ -5,8 +5,11 @@
*/
namespace Magento\Analytics\Model;
+use Magento\Analytics\Model\Config\Backend\Baseurl\SubscriptionUpdateHandler;
use Magento\Analytics\Model\Connector\OTPRequest;
+use Magento\Analytics\Model\Exception\State\SubscriptionUpdateException;
use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\FlagManager;
/**
* Provide URL on resource with reports.
@@ -32,6 +35,11 @@ class ReportUrlProvider
*/
private $config;
+ /**
+ * @var FlagManager
+ */
+ private $flagManager;
+
/**
* Path to config value with URL which provide reports.
*
@@ -43,24 +51,35 @@ class ReportUrlProvider
* @param AnalyticsToken $analyticsToken
* @param OTPRequest $otpRequest
* @param ScopeConfigInterface $config
+ * @param FlagManager $flagManager
*/
public function __construct(
AnalyticsToken $analyticsToken,
OTPRequest $otpRequest,
- ScopeConfigInterface $config
+ ScopeConfigInterface $config,
+ FlagManager $flagManager
) {
$this->analyticsToken = $analyticsToken;
$this->otpRequest = $otpRequest;
$this->config = $config;
+ $this->flagManager = $flagManager;
}
/**
* Provide URL on resource with reports.
*
* @return string
+ * @throws SubscriptionUpdateException
*/
public function getUrl()
{
+ if ($this->flagManager->getFlagData(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE)) {
+ throw new SubscriptionUpdateException(__(
+ 'Your Base URL has been changed and your reports are being updated. '
+ . 'Advanced Reporting will be available once this change has been processed. Please try again later.'
+ ));
+ }
+
$url = $this->config->getValue($this->urlReportConfigPath);
if ($this->analyticsToken->isTokenExist()) {
$otp = $this->otpRequest->call();
diff --git a/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php b/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php
index 8fe548013c206..1dd831a672faa 100644
--- a/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php
+++ b/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php
@@ -5,6 +5,7 @@
*/
namespace Magento\Analytics\Model;
+use Magento\Analytics\Model\Config\Backend\Baseurl\SubscriptionUpdateHandler;
use Magento\Analytics\Model\Config\Backend\Enabled\SubscriptionHandler;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\FlagManager;
@@ -93,6 +94,10 @@ public function getStatus()
public function getStatusForEnabledSubscription()
{
$status = static::ENABLED;
+ if ($this->flagManager->getFlagData(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE)) {
+ $status = self::PENDING;
+ }
+
if (!$this->analyticsToken->isTokenExist()) {
$status = static::PENDING;
if ($this->flagManager->getFlagData(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE) === null) {
diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Reports/ShowTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Reports/ShowTest.php
index eaab952178daa..99de92cc63905 100644
--- a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Reports/ShowTest.php
+++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Reports/ShowTest.php
@@ -6,6 +6,7 @@
namespace Magento\Analytics\Test\Unit\Controller\Adminhtml\Reports;
use Magento\Analytics\Controller\Adminhtml\Reports\Show;
+use Magento\Analytics\Model\Exception\State\SubscriptionUpdateException;
use Magento\Analytics\Model\ReportUrlProvider;
use Magento\Framework\Controller\Result\Redirect;
use Magento\Framework\Controller\ResultFactory;
@@ -152,4 +153,33 @@ public function executeWithExceptionDataProvider()
'ExecuteWithException' => [new \Exception('TestMessage')],
];
}
+
+ /**
+ * @return void
+ */
+ public function testExecuteWithSubscriptionUpdateException()
+ {
+ $exception = new SubscriptionUpdateException(__('TestMessage'));
+ $this->resultFactoryMock
+ ->expects($this->once())
+ ->method('create')
+ ->with(ResultFactory::TYPE_REDIRECT)
+ ->willReturn($this->redirectMock);
+ $this->reportUrlProviderMock
+ ->expects($this->once())
+ ->method('getUrl')
+ ->with()
+ ->willThrowException($exception);
+ $this->messageManagerMock
+ ->expects($this->once())
+ ->method('addNoticeMessage')
+ ->with($exception->getMessage())
+ ->willReturnSelf();
+ $this->redirectMock
+ ->expects($this->once())
+ ->method('setPath')
+ ->with('adminhtml')
+ ->willReturnSelf();
+ $this->assertSame($this->redirectMock, $this->showController->execute());
+ }
}
diff --git a/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php b/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php
index 9a5355de62a5c..23ba59a90ce7b 100644
--- a/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php
+++ b/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php
@@ -6,8 +6,9 @@
namespace Magento\Analytics\Test\Unit\Cron;
use Magento\Analytics\Cron\Update;
+use Magento\Analytics\Model\AnalyticsToken;
+use Magento\Analytics\Model\Config\Backend\Baseurl\SubscriptionUpdateHandler;
use Magento\Analytics\Model\Connector;
-use Magento\Analytics\Model\Plugin\BaseUrlConfigPlugin;
use Magento\Framework\App\Config\ReinitableConfigInterface;
use Magento\Framework\App\Config\Storage\WriterInterface;
use Magento\Framework\FlagManager;
@@ -37,6 +38,11 @@ class UpdateTest extends \PHPUnit_Framework_TestCase
*/
private $reinitableConfigMock;
+ /**
+ * @var AnalyticsToken|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $analyticsTokenMock;
+
/**
* @var Update
*/
@@ -56,38 +62,153 @@ protected function setUp()
$this->reinitableConfigMock = $this->getMockBuilder(ReinitableConfigInterface::class)
->disableOriginalConstructor()
->getMock();
+ $this->analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class)
+ ->disableOriginalConstructor()
+ ->getMock();
$this->update = new Update(
$this->connectorMock,
$this->configWriterMock,
$this->reinitableConfigMock,
- $this->flagManagerMock
+ $this->flagManagerMock,
+ $this->analyticsTokenMock
);
}
- public function testExecute()
+ /**
+ * @return void
+ */
+ public function testExecuteWithoutToken()
{
- $this->connectorMock->expects($this->once())
+ $this->flagManagerMock
+ ->method('getFlagData')
+ ->with(SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE)
+ ->willReturn(10);
+ $this->connectorMock
+ ->expects($this->once())
->method('execute')
->with('update')
- ->willReturn(true);
- $this->configWriterMock->expects($this->once())
- ->method('delete')
- ->with(BaseUrlConfigPlugin::UPDATE_CRON_STRING_PATH);
- $this->flagManagerMock->expects($this->once())
+ ->willReturn(false);
+ $this->analyticsTokenMock
+ ->expects($this->once())
+ ->method('isTokenExist')
+ ->willReturn(false);
+ $this->addFinalOutputAsserts();
+ $this->assertFalse($this->update->execute());
+ }
+
+ /**
+ * @param bool $isExecuted
+ */
+ private function addFinalOutputAsserts(bool $isExecuted = true)
+ {
+ $this->flagManagerMock
+ ->expects($this->exactly(2 * $isExecuted))
->method('deleteFlag')
- ->with(BaseUrlConfigPlugin::OLD_BASE_URL_FLAG_CODE);
- $this->reinitableConfigMock->expects($this->once())
- ->method('reinit');
- $this->assertTrue($this->update->execute());
+ ->withConsecutive(
+ [SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE],
+ [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE]
+ );
+ $this->configWriterMock
+ ->expects($this->exactly((int)$isExecuted))
+ ->method('delete')
+ ->with(SubscriptionUpdateHandler::UPDATE_CRON_STRING_PATH);
+ $this->reinitableConfigMock
+ ->expects($this->exactly((int)$isExecuted))
+ ->method('reinit')
+ ->with();
}
- public function testExecuteUnsuccess()
+ /**
+ * @param $counterData
+ * @return void
+ * @dataProvider executeWithEmptyReverseCounterDataProvider
+ */
+ public function testExecuteWithEmptyReverseCounter($counterData)
{
- $this->connectorMock->expects($this->once())
+ $this->flagManagerMock
+ ->method('getFlagData')
+ ->with(SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE)
+ ->willReturn($counterData);
+ $this->connectorMock
+ ->expects($this->never())
->method('execute')
->with('update')
->willReturn(false);
+ $this->analyticsTokenMock
+ ->method('isTokenExist')
+ ->willReturn(true);
+ $this->addFinalOutputAsserts();
$this->assertFalse($this->update->execute());
}
+
+ /**
+ * Provides empty states of the reverse counter.
+ *
+ * @return array
+ */
+ public function executeWithEmptyReverseCounterDataProvider()
+ {
+ return [
+ [null],
+ [0]
+ ];
+ }
+
+ /**
+ * @param int $reverseCount
+ * @param bool $commandResult
+ * @param bool $finalConditionsIsExpected
+ * @param bool $functionResult
+ * @return void
+ * @dataProvider executeRegularScenarioDataProvider
+ */
+ public function testExecuteRegularScenario(
+ int $reverseCount,
+ bool $commandResult,
+ bool $finalConditionsIsExpected,
+ bool $functionResult
+ ) {
+ $this->flagManagerMock
+ ->method('getFlagData')
+ ->with(SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE)
+ ->willReturn($reverseCount);
+ $this->connectorMock
+ ->expects($this->once())
+ ->method('execute')
+ ->with('update')
+ ->willReturn($commandResult);
+ $this->analyticsTokenMock
+ ->method('isTokenExist')
+ ->willReturn(true);
+ $this->addFinalOutputAsserts($finalConditionsIsExpected);
+ $this->assertSame($functionResult, $this->update->execute());
+ }
+
+ /**
+ * @return array
+ */
+ public function executeRegularScenarioDataProvider()
+ {
+ return [
+ 'The last attempt with command execution result False' => [
+ 'Reverse count' => 1,
+ 'Command result' => false,
+ 'Executed final output conditions' => true,
+ 'Function result' => false,
+ ],
+ 'Not the last attempt with command execution result False' => [
+ 'Reverse count' => 10,
+ 'Command result' => false,
+ 'Executed final output conditions' => false,
+ 'Function result' => false,
+ ],
+ 'Command execution result True' => [
+ 'Reverse count' => 10,
+ 'Command result' => true,
+ 'Executed final output conditions' => true,
+ 'Function result' => true,
+ ],
+ ];
+ }
}
diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Baseurl/SubscriptionUpdateHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Baseurl/SubscriptionUpdateHandlerTest.php
new file mode 100644
index 0000000000000..865ad236fc057
--- /dev/null
+++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Baseurl/SubscriptionUpdateHandlerTest.php
@@ -0,0 +1,178 @@
+reinitableConfigMock = $this->getMockBuilder(ReinitableConfigInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+
+ $this->analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->flagManagerMock = $this->getMockBuilder(FlagManager::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->configWriterMock = $this->getMockBuilder(WriterInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+
+ $this->objectManagerHelper = new ObjectManagerHelper($this);
+
+ $this->subscriptionUpdateHandler = $this->objectManagerHelper->getObject(
+ SubscriptionUpdateHandler::class,
+ [
+ 'reinitableConfig' => $this->reinitableConfigMock,
+ 'analyticsToken' => $this->analyticsTokenMock,
+ 'flagManager' => $this->flagManagerMock,
+ 'configWriter' => $this->configWriterMock,
+ ]
+ );
+ }
+
+ /**
+ * @return void
+ */
+ public function testTokenDoesNotExist()
+ {
+ $this->analyticsTokenMock
+ ->expects($this->once())
+ ->method('isTokenExist')
+ ->with()
+ ->willReturn(false);
+ $this->flagManagerMock
+ ->expects($this->never())
+ ->method('saveFlag');
+ $this->configWriterMock
+ ->expects($this->never())
+ ->method('save');
+ $this->assertTrue($this->subscriptionUpdateHandler->processUrlUpdate('http://store.com'));
+ }
+
+ /**
+ * @return void
+ */
+ public function testTokenAndPreviousBaseUrlExist()
+ {
+ $url = 'https://store.com';
+ $this->analyticsTokenMock
+ ->expects($this->once())
+ ->method('isTokenExist')
+ ->with()
+ ->willReturn(true);
+ $this->flagManagerMock
+ ->expects($this->once())
+ ->method('getFlagData')
+ ->with(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE)
+ ->willReturn(true);
+ $this->flagManagerMock
+ ->expects($this->once())
+ ->method('saveFlag')
+ ->withConsecutive(
+ [SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE, $this->attemptsInitValue],
+ [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, $url]
+ );
+ $this->configWriterMock
+ ->expects($this->once())
+ ->method('save')
+ ->with(SubscriptionUpdateHandler::UPDATE_CRON_STRING_PATH, $this->cronExpression);
+ $this->reinitableConfigMock
+ ->expects($this->once())
+ ->method('reinit')
+ ->with();
+ $this->assertTrue($this->subscriptionUpdateHandler->processUrlUpdate($url));
+ }
+
+ /**
+ * @return void
+ */
+ public function testTokenExistAndWithoutPreviousBaseUrl()
+ {
+ $url = 'https://store.com';
+ $this->analyticsTokenMock
+ ->expects($this->once())
+ ->method('isTokenExist')
+ ->with()
+ ->willReturn(true);
+ $this->flagManagerMock
+ ->expects($this->once())
+ ->method('getFlagData')
+ ->with(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE)
+ ->willReturn(false);
+ $this->flagManagerMock
+ ->expects($this->exactly(2))
+ ->method('saveFlag')
+ ->withConsecutive(
+ [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, $url],
+ [SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE, $this->attemptsInitValue]
+ );
+ $this->configWriterMock
+ ->expects($this->once())
+ ->method('save')
+ ->with(SubscriptionUpdateHandler::UPDATE_CRON_STRING_PATH, $this->cronExpression);
+ $this->reinitableConfigMock
+ ->expects($this->once())
+ ->method('reinit')
+ ->with();
+ $this->assertTrue($this->subscriptionUpdateHandler->processUrlUpdate($url));
+ }
+}
diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php
index a30211c7f3475..5b86dd6557d69 100644
--- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php
+++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php
@@ -8,8 +8,8 @@
use Magento\Analytics\Model\AnalyticsToken;
use Magento\Analytics\Model\Connector\Http\JsonConverter;
use Magento\Analytics\Model\Connector\Http\ResponseResolver;
+use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\HTTP\ZendClient;
-use Magento\Config\Model\Config;
use Psr\Log\LoggerInterface;
use Magento\Analytics\Model\Connector\NotifyDataChangedCommand;
use Magento\Analytics\Model\Connector\Http\ClientInterface;
@@ -32,7 +32,7 @@ class NotifyDataChangedCommandTest extends \PHPUnit_Framework_TestCase
private $httpClientMock;
/**
- * @var Config|\PHPUnit_Framework_MockObject_MockObject
+ * @var ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject
*/
public $configMock;
@@ -51,7 +51,7 @@ protected function setUp()
->disableOriginalConstructor()
->getMock();
- $this->configMock = $this->getMockBuilder(Config::class)
+ $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class)
->disableOriginalConstructor()
->getMock();
@@ -80,7 +80,7 @@ public function testExecuteSuccess()
->method('isTokenExist')
->willReturn(true);
$this->configMock->expects($this->any())
- ->method('getConfigDataValue')
+ ->method('getValue')
->willReturn($configVal);
$this->analyticsTokenMock->expects($this->once())
->method('getToken')
diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php
index 624728f3440c9..cc9eba99b3d48 100644
--- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php
+++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php
@@ -11,7 +11,7 @@
use Magento\Analytics\Model\Connector\SignUpCommand;
use Magento\Analytics\Model\AnalyticsToken;
use Magento\Analytics\Model\IntegrationManager;
-use Magento\Config\Model\Config;
+use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Integration\Model\Oauth\Token as IntegrationToken;
use Psr\Log\LoggerInterface;
@@ -41,7 +41,7 @@ class SignUpCommandTest extends \PHPUnit_Framework_TestCase
private $integrationToken;
/**
- * @var Config|\PHPUnit_Framework_MockObject_MockObject
+ * @var ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject
*/
private $configMock;
@@ -71,7 +71,7 @@ protected function setUp()
$this->integrationToken = $this->getMockBuilder(IntegrationToken::class)
->disableOriginalConstructor()
->getMock();
- $this->configMock = $this->getMockBuilder(Config::class)
+ $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class)
->disableOriginalConstructor()
->getMock();
$this->httpClientMock = $this->getMockBuilder(ClientInterface::class)
@@ -105,7 +105,7 @@ public function testExecuteSuccess()
$data = $this->getTestData();
$this->configMock->expects($this->any())
- ->method('getConfigDataValue')
+ ->method('getValue')
->willReturn($data['url']);
$this->integrationToken->expects($this->any())
->method('getData')
diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php
index c5f96a96b4432..eb22461d789c8 100644
--- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php
+++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php
@@ -6,12 +6,12 @@
namespace Magento\Analytics\Test\Unit\Model\Connector;
use Magento\Analytics\Model\AnalyticsToken;
+use Magento\Analytics\Model\Config\Backend\Baseurl\SubscriptionUpdateHandler;
use Magento\Analytics\Model\Connector\Http\ResponseResolver;
+use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\FlagManager;
use Magento\Framework\HTTP\ZendClient;
-use Magento\Config\Model\Config;
use Psr\Log\LoggerInterface;
-use Magento\Analytics\Model\Plugin\BaseUrlConfigPlugin;
use Magento\Analytics\Model\Connector\UpdateCommand;
use Magento\Analytics\Model\Connector\Http\ClientInterface;
@@ -36,7 +36,7 @@ class UpdateCommandTest extends \PHPUnit_Framework_TestCase
private $httpClientMock;
/**
- * @var Config|\PHPUnit_Framework_MockObject_MockObject
+ * @var ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject
*/
public $configMock;
@@ -65,7 +65,7 @@ protected function setUp()
->disableOriginalConstructor()
->getMock();
- $this->configMock = $this->getMockBuilder(Config::class)
+ $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class)
->disableOriginalConstructor()
->getMock();
@@ -101,12 +101,12 @@ public function testExecuteSuccess()
->willReturn(true);
$this->configMock->expects($this->any())
- ->method('getConfigDataValue')
+ ->method('getValue')
->willReturn($configVal);
$this->flagManagerMock->expects($this->once())
->method('getFlagData')
- ->with(BaseUrlConfigPlugin::OLD_BASE_URL_FLAG_CODE)
+ ->with(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE)
->willReturn($url);
$this->analyticsTokenMock->expects($this->once())
diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php
index caf81b77fbdf9..38d073a4b4550 100644
--- a/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php
+++ b/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php
@@ -5,12 +5,13 @@
*/
namespace Magento\Analytics\Test\Unit\Model\Plugin;
+use Magento\Analytics\Model\Config\Backend\Baseurl\SubscriptionUpdateHandler;
use Magento\Analytics\Model\Plugin\BaseUrlConfigPlugin;
use Magento\Analytics\Model\SubscriptionStatusProvider;
-use Magento\Config\Model\Config\Backend\Baseurl;
-use Magento\Framework\FlagManager;
-use Magento\Framework\App\Config\Storage\WriterInterface;
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\App\Config\Value;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+use Magento\Store\Model\ScopeInterface;
use Magento\Store\Model\Store;
/**
@@ -19,25 +20,15 @@
class BaseUrlConfigPluginTest extends \PHPUnit_Framework_TestCase
{
/**
- * @var FlagManager | \PHPUnit_Framework_MockObject_MockObject
+ * @var SubscriptionUpdateHandler | \PHPUnit_Framework_MockObject_MockObject
*/
- private $flagManagerMock;
+ private $subscriptionUpdateHandlerMock;
/**
- * @var BaseUrl | \PHPUnit_Framework_MockObject_MockObject
+ * @var Value | \PHPUnit_Framework_MockObject_MockObject
*/
private $configValueMock;
- /**
- * @var SubscriptionStatusProvider | \PHPUnit_Framework_MockObject_MockObject
- */
- private $subscriptionStatusProvider;
-
- /**
- * @var WriterInterface | \PHPUnit_Framework_MockObject_MockObject
- */
- private $configWriterMock;
-
/**
* @var ObjectManagerHelper
*/
@@ -53,70 +44,42 @@ class BaseUrlConfigPluginTest extends \PHPUnit_Framework_TestCase
*/
protected function setUp()
{
- $this->flagManagerMock = $this->getMockBuilder(FlagManager::class)
- ->disableOriginalConstructor()
- ->getMock();
- $this->configValueMock = $this->getMockBuilder(Baseurl::class)
+ $this->subscriptionUpdateHandlerMock = $this->getMockBuilder(SubscriptionUpdateHandler::class)
->disableOriginalConstructor()
->getMock();
- $this->subscriptionStatusProvider = $this->getMockBuilder(SubscriptionStatusProvider::class)
+ $this->configValueMock = $this->getMockBuilder(Value::class)
->disableOriginalConstructor()
+ ->setMethods(['isValueChanged', 'getPath', 'getScope', 'getOldValue'])
->getMock();
- $this->configWriterMock = $this->getMockBuilder(WriterInterface::class)
- ->disableOriginalConstructor()
- ->getMockForAbstractClass();
$this->objectManagerHelper = new ObjectManagerHelper($this);
$this->plugin = $this->objectManagerHelper->getObject(
BaseUrlConfigPlugin::class,
[
- 'flagManager' => $this->flagManagerMock,
- 'subscriptionStatusProvider' => $this->subscriptionStatusProvider,
- 'configWriter' => $this->configWriterMock
+ 'subscriptionUpdateHandler' => $this->subscriptionUpdateHandlerMock,
]
);
}
/**
- * @param array $testData
- * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $saveConfigInvokeMatcher
- * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $oldValueInvokeMatcher
- * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $saveFlagInvokeMatcher
- * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $configValueGetPathMatcher
- *
+ * @param array $configValueData
* @return void
- * @dataProvider pluginDataProvider
+ * @dataProvider afterSavePluginIsNotApplicableDataProvider
*/
- public function testPluginForAfterSave(
- array $testData,
- \PHPUnit_Framework_MockObject_Matcher_InvokedCount $saveConfigInvokeMatcher,
- \PHPUnit_Framework_MockObject_Matcher_InvokedCount $oldValueInvokeMatcher,
- \PHPUnit_Framework_MockObject_Matcher_InvokedCount $saveFlagInvokeMatcher,
- \PHPUnit_Framework_MockObject_Matcher_InvokedCount $configValueGetPathMatcher
+ public function testAfterSavePluginIsNotApplicable(
+ array $configValueData
) {
- $this->configValueMock->expects($this->once())
+ $this->configValueMock
->method('isValueChanged')
- ->willReturn($testData['isValueChanged']);
-
- $this->configValueMock->expects($configValueGetPathMatcher)
- ->method('getData')
- ->with('path')
- ->willReturn($testData['path']);
- $this->subscriptionStatusProvider->expects($this->any())->method('getStatus')
- ->willReturn($testData['subscriptionStatus']);
-
- $oldUrl = 'mage.dev';
- $this->configValueMock->expects($oldValueInvokeMatcher)
- ->method('getOldValue')
- ->willReturn($oldUrl);
- $this->flagManagerMock->expects($saveFlagInvokeMatcher)
- ->method('saveFlag')
- ->with(BaseUrlConfigPlugin::OLD_BASE_URL_FLAG_CODE, $oldUrl);
-
- $this->configWriterMock->expects($saveConfigInvokeMatcher)->method('save')
- ->with(
- BaseUrlConfigPlugin::UPDATE_CRON_STRING_PATH,
- '0 * * * *'
- );
+ ->willReturn($configValueData['isValueChanged']);
+ $this->configValueMock
+ ->method('getPath')
+ ->willReturn($configValueData['path']);
+ $this->configValueMock
+ ->method('getScope')
+ ->willReturn($configValueData['scope']);
+ $this->subscriptionUpdateHandlerMock
+ ->expects($this->never())
+ ->method('processUrlUpdate');
$this->assertEquals(
$this->configValueMock,
@@ -127,64 +90,58 @@ public function testPluginForAfterSave(
/**
* @return array
*/
- public function pluginDataProvider()
+ public function afterSavePluginIsNotApplicableDataProvider()
{
return [
- 'setup_subscription_update_cron_job' => [
- 'testData' => [
- 'isValueChanged' => true,
- 'subscriptionStatus' => SubscriptionStatusProvider::ENABLED,
- 'path' => Store::XML_PATH_SECURE_BASE_URL
- ],
- 'saveConfigInvokeMatcher' => $this->once(),
- 'oldValueInvokeMatcher' => $this->once(),
- 'saveFlagInvokeMatcher' => $this->once(),
- 'configValueGetPathMatcher' => $this->once(),
- ],
- 'base_url_not_changed' => [
- 'testData' => [
+ 'Value has not been changed' => [
+ 'Config Value Data' => [
'isValueChanged' => false,
- 'subscriptionStatus' => SubscriptionStatusProvider::ENABLED,
- 'path' => Store::XML_PATH_SECURE_BASE_URL
+ 'path' => Store::XML_PATH_SECURE_BASE_URL,
+ 'scope' => ScopeConfigInterface::SCOPE_TYPE_DEFAULT
],
- 'saveConfigInvokeMatcher' => $this->never(),
- 'oldValueInvokeMatcher' => $this->never(),
- 'saveFlagInvokeMatcher' => $this->never(),
- 'configValueGetPathMatcher' => $this->never(),
],
- 'analytics_disabled' => [
- 'testData' => [
+ 'Unsecure URL has been changed' => [
+ 'Config Value Data' => [
'isValueChanged' => true,
- 'subscriptionStatus' => SubscriptionStatusProvider::DISABLED,
- 'path' => Store::XML_PATH_SECURE_BASE_URL
+ 'path' => Store::XML_PATH_UNSECURE_BASE_URL,
+ 'scope' => ScopeConfigInterface::SCOPE_TYPE_DEFAULT
],
- 'saveConfigInvokeMatcher' => $this->never(),
- 'oldValueInvokeMatcher' => $this->never(),
- 'saveFlagInvokeMatcher' => $this->never(),
- 'configValueGetPathMatcher' => $this->once(),
],
- 'analytics_pending' => [
- 'testData' => [
+ 'Secure URL has been changed not in the Default scope' => [
+ 'Config Value Data' => [
'isValueChanged' => true,
- 'subscriptionStatus' => SubscriptionStatusProvider::PENDING,
- 'path' => Store::XML_PATH_SECURE_BASE_URL
+ 'path' => Store::XML_PATH_SECURE_BASE_URL,
+ 'scope' => ScopeInterface::SCOPE_STORES
],
- 'saveConfigInvokeMatcher' => $this->never(),
- 'oldValueInvokeMatcher' => $this->never(),
- 'saveFlagInvokeMatcher' => $this->never(),
- 'configValueGetPathMatcher' => $this->once(),
],
- 'unsecure_url_changed' => [
- 'testData' => [
- 'isValueChanged' => true,
- 'subscriptionStatus' => SubscriptionStatusProvider::PENDING,
- 'path' => Store::XML_PATH_UNSECURE_BASE_URL
- ],
- 'saveConfigInvokeMatcher' => $this->never(),
- 'oldValueInvokeMatcher' => $this->never(),
- 'saveFlagInvokeMatcher' => $this->never(),
- 'configValueGetPathMatcher' => $this->once(),
- ]
];
}
+
+ /**
+ * @return void
+ */
+ public function testAfterSavePluginIsApplicable()
+ {
+ $this->configValueMock
+ ->method('isValueChanged')
+ ->willReturn(true);
+ $this->configValueMock
+ ->method('getPath')
+ ->willReturn(Store::XML_PATH_SECURE_BASE_URL);
+ $this->configValueMock
+ ->method('getScope')
+ ->willReturn(ScopeConfigInterface::SCOPE_TYPE_DEFAULT);
+ $this->configValueMock
+ ->method('getOldValue')
+ ->willReturn('http://store.com');
+ $this->subscriptionUpdateHandlerMock
+ ->expects($this->once())
+ ->method('processUrlUpdate')
+ ->with('http://store.com');
+
+ $this->assertEquals(
+ $this->configValueMock,
+ $this->plugin->afterAfterSave($this->configValueMock, $this->configValueMock)
+ );
+ }
}
diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php
index 1be0524d72b7f..ee507d88c68db 100644
--- a/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php
+++ b/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php
@@ -6,9 +6,12 @@
namespace Magento\Analytics\Test\Unit\Model;
use Magento\Analytics\Model\AnalyticsToken;
+use Magento\Analytics\Model\Config\Backend\Baseurl\SubscriptionUpdateHandler;
use Magento\Analytics\Model\Connector\OTPRequest;
+use Magento\Analytics\Model\Exception\State\SubscriptionUpdateException;
use Magento\Analytics\Model\ReportUrlProvider;
use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\FlagManager;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
/**
@@ -31,6 +34,11 @@ class ReportUrlProviderTest extends \PHPUnit_Framework_TestCase
*/
private $otpRequestMock;
+ /**
+ * @var FlagManager|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $flagManagerMock;
+
/**
* @var ObjectManagerHelper
*/
@@ -63,6 +71,10 @@ protected function setUp()
->disableOriginalConstructor()
->getMock();
+ $this->flagManagerMock = $this->getMockBuilder(FlagManager::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
$this->objectManagerHelper = new ObjectManagerHelper($this);
$this->reportUrlProvider = $this->objectManagerHelper->getObject(
@@ -71,6 +83,7 @@ protected function setUp()
'config' => $this->configMock,
'analyticsToken' => $this->analyticsTokenMock,
'otpRequest' => $this->otpRequestMock,
+ 'flagManager' => $this->flagManagerMock,
'urlReportConfigPath' => $this->urlReportConfigPath,
]
);
@@ -119,4 +132,22 @@ public function getUrlDataProvider()
'TokenExistAndOtpValid' => [true, '249e6b658877bde2a77bc4ab'],
];
}
+
+ /**
+ * @return void
+ */
+ public function testGetUrlWhenSubscriptionUpdateRunning()
+ {
+ $this->flagManagerMock
+ ->expects($this->once())
+ ->method('getFlagData')
+ ->with(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE)
+ ->willReturn('http://store.com');
+ $this->setExpectedException(
+ SubscriptionUpdateException::class,
+ 'Your Base URL has been changed and your reports are being updated. '
+ . 'Advanced Reporting will be available once this change has been processed. Please try again later.'
+ );
+ $this->reportUrlProvider->getUrl();
+ }
}
diff --git a/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php
index 90707b2db7e1a..2e52a13f90bbf 100644
--- a/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php
+++ b/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php
@@ -6,6 +6,7 @@
namespace Magento\Analytics\Test\Unit\Model;
use Magento\Analytics\Model\AnalyticsToken;
+use Magento\Analytics\Model\Config\Backend\Baseurl\SubscriptionUpdateHandler;
use Magento\Analytics\Model\Config\Backend\Enabled\SubscriptionHandler;
use Magento\Analytics\Model\SubscriptionStatusProvider;
use Magento\Framework\App\Config\ScopeConfigInterface;
@@ -70,7 +71,11 @@ protected function setUp()
);
}
- public function testGetStatusShouldBeFailed()
+ /**
+ * @param array $flagManagerData
+ * @dataProvider getStatusShouldBeFailedDataProvider
+ */
+ public function testGetStatusShouldBeFailed(array $flagManagerData)
{
$this->analyticsTokenMock->expects($this->once())
->method('isTokenExist')
@@ -80,26 +85,86 @@ public function testGetStatusShouldBeFailed()
->with('analytics/subscription/enabled')
->willReturn(true);
- $this->expectFlagCounterReturn(null);
+ $this->expectFlagManagerReturn($flagManagerData);
$this->assertEquals(SubscriptionStatusProvider::FAILED, $this->statusProvider->getStatus());
}
- public function testGetStatusShouldBePending()
+ /**
+ * @return array
+ */
+ public function getStatusShouldBeFailedDataProvider()
+ {
+ return [
+ 'Subscription update doesn\'t active' => [
+ 'Flag Manager data mapping' => [
+ [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, null],
+ [SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, null]
+ ],
+ ],
+ 'Subscription update is active' => [
+ 'Flag Manager data mapping' => [
+ [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, 'http://store.com'],
+ [SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, null]
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * @param array $flagManagerData
+ * @param bool $isTokenExist
+ * @dataProvider getStatusShouldBePendingDataProvider
+ */
+ public function testGetStatusShouldBePending(array $flagManagerData, bool $isTokenExist)
{
$this->analyticsTokenMock->expects($this->once())
->method('isTokenExist')
- ->willReturn(false);
+ ->willReturn($isTokenExist);
$this->scopeConfigMock->expects($this->once())
->method('getValue')
->with('analytics/subscription/enabled')
->willReturn(true);
- $this->expectFlagCounterReturn(45);
+ $this->expectFlagManagerReturn($flagManagerData);
$this->assertEquals(SubscriptionStatusProvider::PENDING, $this->statusProvider->getStatus());
}
+ /**
+ * @return array
+ */
+ public function getStatusShouldBePendingDataProvider()
+ {
+ return [
+ 'Subscription update doesn\'t active and the token does not exist' => [
+ 'Flag Manager data mapping' => [
+ [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, null],
+ [SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, 45]
+ ],
+ 'isTokenExist' => false,
+ ],
+ 'Subscription update is active and the token does not exist' => [
+ 'Flag Manager data mapping' => [
+ [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, 'http://store.com'],
+ [SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, 45]
+ ],
+ 'isTokenExist' => false,
+ ],
+ 'Subscription update is active and token exist' => [
+ 'Flag Manager data mapping' => [
+ [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, 'http://store.com'],
+ [SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, null]
+ ],
+ 'isTokenExist' => true,
+ ],
+ ];
+ }
+
public function testGetStatusShouldBeEnabled()
{
+ $this->flagManagerMock
+ ->method('getFlagData')
+ ->with(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE)
+ ->willReturn(null);
$this->analyticsTokenMock->expects($this->once())
->method('isTokenExist')
->willReturn(true);
@@ -120,15 +185,12 @@ public function testGetStatusShouldBeDisabled()
}
/**
- * @param null|int $value
+ * @param array $mapping
*/
- private function expectFlagCounterReturn($value)
+ private function expectFlagManagerReturn(array $mapping)
{
- $this->flagManagerMock->expects($this->once())->method('getFlagData')
- ->willReturnMap(
- [
- [SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, $value],
- ]
- );
+ $this->flagManagerMock
+ ->method('getFlagData')
+ ->willReturnMap($mapping);
}
}
diff --git a/app/code/Magento/Analytics/composer.json b/app/code/Magento/Analytics/composer.json
index edc3443e487b6..bdea53c445a34 100644
--- a/app/code/Magento/Analytics/composer.json
+++ b/app/code/Magento/Analytics/composer.json
@@ -3,14 +3,14 @@
"description": "N/A",
"require": {
"php": "7.0.2|7.0.4|~7.0.6|~7.1.0",
- "magento/module-backend": "100.2.*",
- "magento/module-config": "100.2.*",
- "magento/module-integration": "100.2.*",
- "magento/module-store": "100.2.*",
- "magento/framework": "100.2.*"
+ "magento/module-backend": "100.3.*",
+ "magento/module-config": "100.3.*",
+ "magento/module-integration": "100.3.*",
+ "magento/module-store": "100.3.*",
+ "magento/framework": "100.3.*"
},
"type": "magento2-module",
- "version": "100.2.0-dev",
+ "version": "100.3.0-dev",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/Analytics/etc/di.xml b/app/code/Magento/Analytics/etc/di.xml
index 4b4cef4c1a80e..09efd7c36ad83 100644
--- a/app/code/Magento/Analytics/etc/di.xml
+++ b/app/code/Magento/Analytics/etc/di.xml
@@ -181,28 +181,28 @@
- Apps and Games
- Athletic/Sporting Goods
- Art and Design
- Auto Parts
- Baby/Children’s Apparel, Gear and Toys
- Beauty and Cosmetics
- Books, Music and Magazines
- Crafts and Stationery
- Consumer Electronics
- Deal Site
- Fashion Apparel and Accessories
- Food, Beverage and Grocery
- Home Goods and Furniture
- Home Improvement
- Jewelry and Watches
- Mass Merchant
- Office Supplies
- Outdoor and Camping Gear
- Pet Goods
- Pharma and Medical Devices
- Technology B2B
- Other
+ Apps and Games
+ Athletic/Sporting Goods
+ Art and Design
+ Auto Parts
+ Baby/Children’s Apparel, Gear and Toys
+ Beauty and Cosmetics
+ Books, Music and Magazines
+ Crafts and Stationery
+ Consumer Electronics
+ Deal Site
+ Fashion Apparel and Accessories
+ Food, Beverage and Grocery
+ Home Goods and Furniture
+ Home Improvement
+ Jewelry and Watches
+ Mass Merchant
+ Office Supplies
+ Outdoor and Camping Gear
+ Pet Goods
+ Pharma and Medical Devices
+ Technology B2B
+ Other
diff --git a/app/code/Magento/Analytics/i18n/en_US.csv b/app/code/Magento/Analytics/i18n/en_US.csv
new file mode 100644
index 0000000000000..090534923e450
--- /dev/null
+++ b/app/code/Magento/Analytics/i18n/en_US.csv
@@ -0,0 +1,103 @@
+"Subscription status","Subscription status"
+"Sorry, there has been an error processing your request. Please try again later.","Sorry, there has been an error processing your request. Please try again later."
+"Sorry, there was an error processing your registration request to Magento Analytics. Please try again later.","Sorry, there was an error processing your registration request to Magento Analytics. Please try again later."
+"Error occurred during postponement notification","Error occurred during postponement notification"
+"Time value has an unsupported format","Time value has an unsupported format"
+"Cron settings can't be saved","Cron settings can't be saved"
+"There was an error save new configuration value.","There was an error save new configuration value."
+"Please select a vertical.","Please select a vertical."
+"--Please Select--","--Please Select--"
+"Command was not found.","Command was not found."
+"Input data must be string or convertible into string.","Input data must be string or convertible into string."
+"Input data must be non-empty string.","Input data must be non-empty string."
+"Not valid cipher method.","Not valid cipher method."
+"Encryption key can't be empty.","Encryption key can't be empty."
+"Source ""%1"" is not exist","Source ""%1"" is not exist"
+"These arguments can't be empty ""%1""","These arguments can't be empty ""%1"""
+"Cannot find predefined integration user!","Cannot find predefined integration user!"
+"File is not ready yet.","File is not ready yet."
+"Your Base URL has been changed and your reports are being updated. Advanced Reporting will be available once this change has been processed. Please try again later.","Your Base URL has been changed and your reports are being updated. Advanced Reporting will be available once this change has been processed. Please try again later."
+"Failed to synchronize data to the Magento Business Intelligence service. ","Failed to synchronize data to the Magento Business Intelligence service. "
+"Retry Synchronization","Retry Synchronization"
+TestMessage,TestMessage
+"Error message","Error message"
+"Apps and Games","Apps and Games"
+"Athletic/Sporting Goods","Athletic/Sporting Goods"
+"Art and Design","Art and Design"
+"Advanced Reporting","Advanced Reporting"
+"Gain new insights and take command of your business' performance, using our dynamic product, order, and customer reports tailored to your customer data.","Gain new insights and take command of your business' performance, using our dynamic product, order, and customer reports tailored to your customer data."
+"View details","View details"
+"Go to Advanced Reporting","Go to Advanced Reporting"
+"An error occurred while subscription process.","An error occurred while subscription process."
+Analytics,Analytics
+API,API
+Configuration,Configuration
+"Business Intelligence","Business Intelligence"
+"BI Essentials","BI Essentials"
+"This service provides a suite of dynamic reports based on your product, order and
+ customer data. All reports are accessed securely on a personalized dashboard dedicated to your reports -
+ separate from your Admin Panel. For more information, view details or see our
+ terms and conditions.","This service provides a suite of dynamic reports based on your product, order and
+ customer data. All reports are accessed securely on a personalized dashboard dedicated to your reports -
+ separate from your Admin Panel. For more information, view details or see our
+ terms and conditions."
+"Advanced Reporting Service","Advanced Reporting Service"
+Industry,Industry
+"Time of day to send data","Time of day to send data"
+"Get more insights from Magento Business Intelligence","Get more insights from Magento Business Intelligence"
+"Magento Business Intelligence provides you with a simple and clear path to
+ becoming more data driven. Learn more about BI Essentials tier.","Magento Business Intelligence provides you with a simple and clear path to
+ becoming more data driven. Learn more about BI Essentials tier."
+"Auto Parts","Auto Parts"
+"Baby/Children’s Apparel, Gear and Toys","Baby/Children’s Apparel, Gear and Toys"
+"Beauty and Cosmetics","Beauty and Cosmetics"
+"Books, Music and Magazines","Books, Music and Magazines"
+"Crafts and Stationery","Crafts and Stationery"
+"Consumer Electronics","Consumer Electronics"
+"Deal Site","Deal Site"
+"Fashion Apparel and Accessories","Fashion Apparel and Accessories"
+"Food, Beverage and Grocery","Food, Beverage and Grocery"
+"Home Goods and Furniture","Home Goods and Furniture"
+"Home Improvement","Home Improvement"
+"Jewelry and Watches","Jewelry and Watches"
+"Mass Merchant","Mass Merchant"
+"Office Supplies","Office Supplies"
+"Outdoor and Camping Gear","Outdoor and Camping Gear"
+"Pet Goods","Pet Goods"
+"Pharma and Medical Devices","Pharma and Medical Devices"
+"Technology B2B","Technology B2B"
+"Analytics Subscription","Analytics Subscription"
+"powered by Magento Business Intelligence","powered by Magento Business Intelligence"
+"
When you turn on Advanced
+ Reporting, you'll have access to a suite of dynamic reports tailored to your business. Example
+ of the new data and trend reports, listed by category, include:
+
Order: Number of orders, total revenue, and AOV
Customer:
+ New registered accounts, unique customers, number of orders, AOV, revenue by email
+
Product: Quantity sold, bestsellers by volume/revenue
A
+ personalized dashboard includes all reports - separate from your Admin Panel, yet still at your
+ fingertips.
We're excited to offer these valuable tools that can help your business become
+ more data-driven. For more information, view details or see our
+ terms and conditions.
+ ","
When you turn on Advanced
+ Reporting, you'll have access to a suite of dynamic reports tailored to your business. Example
+ of the new data and trend reports, listed by category, include:
+
Order: Number of orders, total revenue, and AOV
Customer:
+ New registered accounts, unique customers, number of orders, AOV, revenue by email
+
Product: Quantity sold, bestsellers by volume/revenue
A
+ personalized dashboard includes all reports - separate from your Admin Panel, yet still at your
+ fingertips.
We're excited to offer these valuable tools that can help your business become
+ more data-driven. For more information, view details or see our
+ terms and conditions.
+ "
+"Are you sure you want to opt out?","Are you sure you want to opt out?"
+Cancel,Cancel
+"Opt out","Opt out"
+"
Advanced Reporting in included,
+ free of charge, in your Magento software. When you opt out, we collect no product, order, and
+ customer data to generate our dynamic reports.
To opt in later: You can always turn on Advanced
+ Reporting in you Admin Panel.
","
Advanced Reporting in included,
+ free of charge, in your Magento software. When you opt out, we collect no product, order, and
+ customer data to generate our dynamic reports.
To opt in later: You can always turn on Advanced
+ Reporting in you Admin Panel.
diff --git a/app/code/Magento/Ups/composer.json b/app/code/Magento/Ups/composer.json
index 90ec2a62b89c5..3a6ee38593717 100644
--- a/app/code/Magento/Ups/composer.json
+++ b/app/code/Magento/Ups/composer.json
@@ -3,20 +3,20 @@
"description": "N/A",
"require": {
"php": "7.0.2|7.0.4|~7.0.6|~7.1.0",
- "magento/module-store": "100.2.*",
- "magento/module-backend": "100.2.*",
- "magento/module-sales": "100.2.*",
- "magento/module-shipping": "100.2.*",
- "magento/module-directory": "100.2.*",
- "magento/module-catalog-inventory": "100.2.*",
- "magento/module-quote": "100.2.*",
- "magento/framework": "100.2.*"
+ "magento/module-store": "100.3.*",
+ "magento/module-backend": "100.3.*",
+ "magento/module-sales": "100.3.*",
+ "magento/module-shipping": "100.3.*",
+ "magento/module-directory": "100.3.*",
+ "magento/module-catalog-inventory": "100.3.*",
+ "magento/module-quote": "100.3.*",
+ "magento/framework": "100.3.*"
},
"suggest": {
- "magento/module-config": "100.2.*"
+ "magento/module-config": "100.3.*"
},
"type": "magento2-module",
- "version": "100.2.0-dev",
+ "version": "100.3.0-dev",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/Ups/i18n/en_US.csv b/app/code/Magento/Ups/i18n/en_US.csv
index 10a30440262e5..0412a993b00ef 100644
--- a/app/code/Magento/Ups/i18n/en_US.csv
+++ b/app/code/Magento/Ups/i18n/en_US.csv
@@ -59,8 +59,8 @@ Residential,Residential
Commercial,Commercial
Pounds,Pounds
Kilograms,Kilograms
-"Sorry, something went wrong. Please try again or contact us and we\'ll try to help.","Sorry, something went wrong. Please try again or contact us and we\'ll try to help."
-"We can\'t convert a rate from ""%1-%2"".","We can\'t convert a rate from ""%1-%2""."
+"Sorry, something went wrong. Please try again or contact us and we'll try to help.","Sorry, something went wrong. Please try again or contact us and we'll try to help."
+"We can't convert a rate from ""%1-%2"".","We can't convert a rate from ""%1-%2""."
"Cannot retrieve shipping rates","Cannot retrieve shipping rates"
status,status
error_message,error_message
@@ -81,6 +81,7 @@ UPS,UPS
"Allowed Methods","Allowed Methods"
"Packages Request Type","Packages Request Type"
Container,Container
+"Enable Free Shipping Threshold","Enable Free Shipping Threshold"
"Free Shipping Amount Threshold","Free Shipping Amount Threshold"
"Destination Type","Destination Type"
"Free Method","Free Method"
diff --git a/app/code/Magento/UrlRewrite/Model/Exception/UrlAlreadyExistsException.php b/app/code/Magento/UrlRewrite/Model/Exception/UrlAlreadyExistsException.php
new file mode 100644
index 0000000000000..5ffeae20fc1d6
--- /dev/null
+++ b/app/code/Magento/UrlRewrite/Model/Exception/UrlAlreadyExistsException.php
@@ -0,0 +1,42 @@
+urls = $urls;
+ if ($phrase === null) {
+ $phrase = __('URL key for specified store already exists');
+ }
+ parent::__construct($phrase, $cause, $code);
+ }
+
+ /**
+ * @return array
+ */
+ public function getUrls()
+ {
+ return $this->urls;
+ }
+}
diff --git a/app/code/Magento/UrlRewrite/Model/Message/UrlRewriteExceptionMessageFactory.php b/app/code/Magento/UrlRewrite/Model/Message/UrlRewriteExceptionMessageFactory.php
new file mode 100644
index 0000000000000..65c254b6866d9
--- /dev/null
+++ b/app/code/Magento/UrlRewrite/Model/Message/UrlRewriteExceptionMessageFactory.php
@@ -0,0 +1,63 @@
+messageFactory = $messageFactory;
+ $this->urlBuilder = $urlBuilder;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function createMessage(\Exception $exception, $type = MessageInterface::TYPE_ERROR)
+ {
+ if ($exception instanceof UrlAlreadyExistsException) {
+ $generatedUrls = [];
+ $urls = $exception->getUrls();
+ if ($urls && is_array($urls)) {
+ foreach ($urls as $id => $url) {
+ $adminEditUrl = $this->urlBuilder->getUrl(
+ 'adminhtml/url_rewrite/edit',
+ ['id' => $id]
+ );
+ $generatedUrls[$adminEditUrl] = $url['request_path'];
+ }
+ }
+ return $this->messageFactory->create($type)
+ ->setIdentifier(self::URL_DUPLICATE_MESSAGE_MAP_ID)
+ ->setText($exception->getMessage())
+ ->setData(['urls' => $generatedUrls]);
+ }
+ throw new RuntimeException(
+ __('Exception instance doesn\'t match %1 type', UrlAlreadyExistsException::class)
+ );
+ }
+}
diff --git a/app/code/Magento/UrlRewrite/Model/Storage/AbstractStorage.php b/app/code/Magento/UrlRewrite/Model/Storage/AbstractStorage.php
index 6296f0acbfe83..86e6d98ea0e85 100644
--- a/app/code/Magento/UrlRewrite/Model/Storage/AbstractStorage.php
+++ b/app/code/Magento/UrlRewrite/Model/Storage/AbstractStorage.php
@@ -24,8 +24,10 @@ abstract class AbstractStorage implements StorageInterface
* @param UrlRewriteFactory $urlRewriteFactory
* @param DataObjectHelper $dataObjectHelper
*/
- public function __construct(UrlRewriteFactory $urlRewriteFactory, DataObjectHelper $dataObjectHelper)
- {
+ public function __construct(
+ UrlRewriteFactory $urlRewriteFactory,
+ DataObjectHelper $dataObjectHelper
+ ) {
$this->urlRewriteFactory = $urlRewriteFactory;
$this->dataObjectHelper = $dataObjectHelper;
}
@@ -50,7 +52,7 @@ public function findAllByData(array $data)
* @param array $data
* @return array
*/
- abstract protected function doFindAllByData($data);
+ abstract protected function doFindAllByData(array $data);
/**
* {@inheritdoc}
@@ -68,7 +70,7 @@ public function findOneByData(array $data)
* @param array $data
* @return array
*/
- abstract protected function doFindOneByData($data);
+ abstract protected function doFindOneByData(array $data);
/**
* {@inheritdoc}
@@ -76,26 +78,19 @@ abstract protected function doFindOneByData($data);
public function replace(array $urls)
{
if (!$urls) {
- return;
- }
-
- try {
- $this->doReplace($urls);
- } catch (\Magento\Framework\Exception\AlreadyExistsException $e) {
- throw new \Magento\Framework\Exception\AlreadyExistsException(
- __('URL key for specified store already exists.')
- );
+ return [];
}
+ return $this->doReplace($urls);
}
/**
* Save new url rewrites and remove old if exist. Template method
*
* @param \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[] $urls
- * @return int
- * @throws \Magento\Framework\Exception\AlreadyExistsException
+ * @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[]
+ * @throws \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException|\Exception
*/
- abstract protected function doReplace($urls);
+ abstract protected function doReplace(array $urls);
/**
* Create url rewrite object
diff --git a/app/code/Magento/UrlRewrite/Model/Storage/DbStorage.php b/app/code/Magento/UrlRewrite/Model/Storage/DbStorage.php
index 76a6d30d606df..376b07a17fe6a 100644
--- a/app/code/Magento/UrlRewrite/Model/Storage/DbStorage.php
+++ b/app/code/Magento/UrlRewrite/Model/Storage/DbStorage.php
@@ -10,6 +10,8 @@
use Magento\UrlRewrite\Model\OptionProvider;
use Magento\UrlRewrite\Service\V1\Data\UrlRewrite;
use Magento\UrlRewrite\Service\V1\Data\UrlRewriteFactory;
+use Psr\Log\LoggerInterface;
+use Magento\UrlRewrite\Service\V1\Data\UrlRewrite as UrlRewriteData;
class DbStorage extends AbstractStorage
{
@@ -21,7 +23,7 @@ class DbStorage extends AbstractStorage
/**
* Code of "Integrity constraint violation: 1062 Duplicate entry" error
*/
- const ERROR_CODE_DUPLICATE_ENTRY = 23000;
+ const ERROR_CODE_DUPLICATE_ENTRY = 1062;
/**
* @var \Magento\Framework\DB\Adapter\AdapterInterface
@@ -33,18 +35,27 @@ class DbStorage extends AbstractStorage
*/
protected $resource;
+ /**
+ * @var \Psr\Log\LoggerInterface
+ */
+ private $logger;
+
/**
* @param \Magento\UrlRewrite\Service\V1\Data\UrlRewriteFactory $urlRewriteFactory
* @param DataObjectHelper $dataObjectHelper
* @param \Magento\Framework\App\ResourceConnection $resource
+ * @param \Psr\Log\LoggerInterface|null $logger
*/
public function __construct(
UrlRewriteFactory $urlRewriteFactory,
DataObjectHelper $dataObjectHelper,
- ResourceConnection $resource
+ ResourceConnection $resource,
+ LoggerInterface $logger = null
) {
$this->connection = $resource->getConnection();
$this->resource = $resource;
+ $this->logger = $logger ?: \Magento\Framework\App\ObjectManager::getInstance()
+ ->get(\Psr\Log\LoggerInterface::class);
parent::__construct($urlRewriteFactory, $dataObjectHelper);
}
@@ -55,7 +66,7 @@ public function __construct(
* @param array $data
* @return \Magento\Framework\DB\Select
*/
- protected function prepareSelect($data)
+ protected function prepareSelect(array $data)
{
$select = $this->connection->select();
$select->from($this->resource->getTableName(self::TABLE_NAME));
@@ -69,7 +80,7 @@ protected function prepareSelect($data)
/**
* {@inheritdoc}
*/
- protected function doFindAllByData($data)
+ protected function doFindAllByData(array $data)
{
return $this->connection->fetchAll($this->prepareSelect($data));
}
@@ -77,10 +88,9 @@ protected function doFindAllByData($data)
/**
* {@inheritdoc}
*/
- protected function doFindOneByData($data)
+ protected function doFindOneByData(array $data)
{
- if (is_array($data)
- && array_key_exists(UrlRewrite::REQUEST_PATH, $data)
+ if (array_key_exists(UrlRewrite::REQUEST_PATH, $data)
&& is_string($data[UrlRewrite::REQUEST_PATH])
) {
$result = null;
@@ -133,7 +143,7 @@ protected function doFindOneByData($data)
/**
* {@inheritdoc}
*/
- protected function doReplace($urls)
+ protected function doReplace(array $urls)
{
foreach ($this->createFilterDataBasedOnUrls($urls) as $type => $urlData) {
$urlData[UrlRewrite::ENTITY_TYPE] = $type;
@@ -143,7 +153,35 @@ protected function doReplace($urls)
foreach ($urls as $url) {
$data[] = $url->toArray();
}
- $this->insertMultiple($data);
+ try {
+ $this->insertMultiple($data);
+ } catch (\Magento\Framework\Exception\AlreadyExistsException $e) {
+ /** @var \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[] $urlConflicted */
+ $urlConflicted = [];
+ foreach ($urls as $url) {
+ $urlFound = $this->doFindOneByData(
+ [
+ UrlRewriteData::REQUEST_PATH => $url->getRequestPath(),
+ UrlRewriteData::STORE_ID => $url->getStoreId()
+ ]
+ );
+ if (isset($urlFound[UrlRewriteData::URL_REWRITE_ID])) {
+ $urlConflicted[$urlFound[UrlRewriteData::URL_REWRITE_ID]] = $url->toArray();
+ }
+ }
+ if ($urlConflicted) {
+ throw new \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException(
+ __('URL key for specified store already exists.'),
+ $e,
+ $e->getCode(),
+ $urlConflicted
+ );
+ } else {
+ throw $e->getPrevious() ?: $e;
+ }
+ }
+
+ return $urls;
}
/**
@@ -151,7 +189,7 @@ protected function doReplace($urls)
*
* @param array $data
* @return void
- * @throws \Magento\Framework\Exception\AlreadyExistsException
+ * @throws \Magento\Framework\Exception\AlreadyExistsException|\Exception
* @throws \Exception
*/
protected function insertMultiple($data)
@@ -159,11 +197,12 @@ protected function insertMultiple($data)
try {
$this->connection->insertMultiple($this->resource->getTableName(self::TABLE_NAME), $data);
} catch (\Exception $e) {
- if ($e->getCode() === self::ERROR_CODE_DUPLICATE_ENTRY
+ if (($e->getCode() === self::ERROR_CODE_DUPLICATE_ENTRY)
&& preg_match('#SQLSTATE\[23000\]: [^:]+: 1062[^\d]#', $e->getMessage())
) {
throw new \Magento\Framework\Exception\AlreadyExistsException(
- __('URL key for specified store already exists.')
+ __('URL key for specified store already exists.'),
+ $e
);
}
throw $e;
diff --git a/app/code/Magento/UrlRewrite/Model/UrlPersistInterface.php b/app/code/Magento/UrlRewrite/Model/UrlPersistInterface.php
index d1ec01b5a2d9f..3a36b870b30b4 100644
--- a/app/code/Magento/UrlRewrite/Model/UrlPersistInterface.php
+++ b/app/code/Magento/UrlRewrite/Model/UrlPersistInterface.php
@@ -15,8 +15,8 @@ interface UrlPersistInterface
* Save new url rewrites and remove old if exist
*
* @param \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[] $urls
- * @return void
- * @throws \Magento\Framework\Exception\AlreadyExistsException
+ * @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[]
+ * @throws \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException|\Exception
*/
public function replace(array $urls);
diff --git a/app/code/Magento/UrlRewrite/Test/Unit/Model/Exception/UrlAlreadyExistsExceptionTest.php b/app/code/Magento/UrlRewrite/Test/Unit/Model/Exception/UrlAlreadyExistsExceptionTest.php
new file mode 100644
index 0000000000000..cb3e3de4e2d3c
--- /dev/null
+++ b/app/code/Magento/UrlRewrite/Test/Unit/Model/Exception/UrlAlreadyExistsExceptionTest.php
@@ -0,0 +1,69 @@
+defaultRenderer = \Magento\Framework\Phrase::getRenderer();
+ $rendererMock = $this->getMockBuilder(\Magento\Framework\Phrase\Renderer\Placeholder::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->renderedMessage = 'rendered message';
+ $rendererMock->expects($this->once())
+ ->method('render')
+ ->will($this->returnValue($this->renderedMessage));
+ \Magento\Framework\Phrase::setRenderer($rendererMock);
+ }
+
+ /**
+ * @return void
+ */
+ public function tearDown()
+ {
+ \Magento\Framework\Phrase::setRenderer($this->defaultRenderer);
+ }
+
+ public function testUrls()
+ {
+ $expectedCode = 42;
+ $urls = ['someUrl.html'];
+ $localizedException = new UrlAlreadyExistsException(
+ new Phrase("message %1", ['test']),
+ new \Exception(),
+ $expectedCode,
+ $urls
+ );
+
+ $this->assertEquals($urls, $localizedException->getUrls());
+ }
+
+ public function testDefaultPhrase()
+ {
+ $localizedException = new UrlAlreadyExistsException();
+
+ $this->assertEquals(
+ 'rendered message',
+ $localizedException->getMessage()
+ );
+ }
+}
diff --git a/app/code/Magento/UrlRewrite/Test/Unit/Model/Message/UrlRewriteExceptionMessageFactoryTest.php b/app/code/Magento/UrlRewrite/Test/Unit/Model/Message/UrlRewriteExceptionMessageFactoryTest.php
new file mode 100644
index 0000000000000..bde3c6a84e1bf
--- /dev/null
+++ b/app/code/Magento/UrlRewrite/Test/Unit/Model/Message/UrlRewriteExceptionMessageFactoryTest.php
@@ -0,0 +1,97 @@
+urlMock = $this->getMock(\Magento\Framework\UrlInterface::class);
+
+ $this->messageFactoryMock = $this->getMock(
+ \Magento\Framework\Message\Factory::class,
+ ['create'],
+ [],
+ '',
+ false
+ );
+
+ $this->urlRewriteExceptionMessageFactory = new UrlRewriteExceptionMessageFactory(
+ $this->messageFactoryMock,
+ $this->urlMock
+ );
+ }
+
+ public function testCreateMessage()
+ {
+ $exception = new \Exception('exception');
+ $urlAlreadyExistsException = new UrlAlreadyExistsException(
+ __('message'),
+ $exception,
+ 0,
+ [['request_path' => 'url']]
+ );
+
+ $this->urlMock->expects($this->once())
+ ->method('getUrl')
+ ->willReturn('htmlUrl');
+
+ $message = $this->getMock(MessageInterface::class);
+
+ $message->expects($this->once())
+ ->method('setText')
+ ->with($urlAlreadyExistsException->getMessage())
+ ->willReturn($message);
+
+ $message->expects($this->once())
+ ->method('setIdentifier')
+ ->with(UrlRewriteExceptionMessageFactory::URL_DUPLICATE_MESSAGE_MAP_ID)
+ ->willReturnSelf();
+
+ $message->expects($this->once())
+ ->method('setData')
+ ->with(['urls' => ['htmlUrl' => 'url']])
+ ->willReturn($message);
+
+ $this->messageFactoryMock->expects($this->once())
+ ->method('create')
+ ->with(MessageInterface::TYPE_ERROR)
+ ->willReturn($message);
+
+ $this->assertEquals(
+ $message,
+ $this->urlRewriteExceptionMessageFactory->createMessage($urlAlreadyExistsException)
+ );
+ }
+
+ /**
+ * @expectedException \Magento\Framework\Exception\RuntimeException
+ */
+ public function testCreateMessageNotFound()
+ {
+ $exception = new \Exception('message');
+ $this->urlRewriteExceptionMessageFactory->createMessage($exception);
+ }
+}
diff --git a/app/code/Magento/UrlRewrite/Test/Unit/Model/Storage/AbstractStorageTest.php b/app/code/Magento/UrlRewrite/Test/Unit/Model/Storage/AbstractStorageTest.php
index ee2069aaa7549..f43ed3ea7faed 100644
--- a/app/code/Magento/UrlRewrite/Test/Unit/Model/Storage/AbstractStorageTest.php
+++ b/app/code/Magento/UrlRewrite/Test/Unit/Model/Storage/AbstractStorageTest.php
@@ -115,8 +115,8 @@ public function testReplaceIfUrlsAreEmpty()
}
/**
- * @expectedException \Magento\Framework\Exception\AlreadyExistsException
- * @expectedExceptionMessage URL key for specified store already exists.
+ * @expectedException \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException
+ * @expectedExceptionMessage Custom storage message
*/
public function testReplaceIfThrewDuplicateEntryExceptionWithCustomMessage()
{
@@ -124,7 +124,23 @@ public function testReplaceIfThrewDuplicateEntryExceptionWithCustomMessage()
->expects($this->once())
->method('doReplace')
->will($this->throwException(
- new \Magento\Framework\Exception\AlreadyExistsException(__('Custom storage message'))
+ new \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException(__('Custom storage message'))
+ ));
+
+ $this->storage->replace([['UrlRewrite1']]);
+ }
+
+ /**
+ * @expectedException \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException
+ * @expectedExceptionMessage URL key for specified store already exists
+ */
+ public function testReplaceIfThrewDuplicateEntryExceptionDefaultMessage()
+ {
+ $this->storage
+ ->expects($this->once())
+ ->method('doReplace')
+ ->will($this->throwException(
+ new \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException()
));
$this->storage->replace([['UrlRewrite1']]);
diff --git a/app/code/Magento/UrlRewrite/Test/Unit/Model/Storage/DbStorageTest.php b/app/code/Magento/UrlRewrite/Test/Unit/Model/Storage/DbStorageTest.php
index 74204dc5a0b3b..99447c7ceab0d 100644
--- a/app/code/Magento/UrlRewrite/Test/Unit/Model/Storage/DbStorageTest.php
+++ b/app/code/Magento/UrlRewrite/Test/Unit/Model/Storage/DbStorageTest.php
@@ -531,9 +531,42 @@ public function testReplace()
}
/**
- * @expectedException \Magento\Framework\Exception\AlreadyExistsException
+ * @expectedException \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException
*/
- public function testReplaceIfThrewDuplicateEntryException()
+ public function testReplaceIfThrewExceptionOnDuplicateUrl()
+ {
+ $url = $this->getMock(\Magento\UrlRewrite\Service\V1\Data\UrlRewrite::class, [], [], '', false);
+
+ $url->expects($this->any())
+ ->method('toArray')
+ ->will($this->returnValue(['row1']));
+
+ $this->connectionMock->expects($this->once())
+ ->method('insertMultiple')
+ ->will(
+ $this->throwException(
+ new \Exception('SQLSTATE[23000]: test: 1062 test', DbStorage::ERROR_CODE_DUPLICATE_ENTRY)
+ )
+ );
+ $conflictingUrl = [
+ UrlRewrite::URL_REWRITE_ID => 'conflicting-url'
+ ];
+ $this->connectionMock->expects($this->any())
+ ->method('fetchRow')
+ ->willReturn($conflictingUrl);
+
+ $this->storage->replace([$url]);
+ }
+
+ /**
+ * Validates a case when DB errors on duplicate entry, but calculated URLs are not really duplicated
+ *
+ * An example is when URL length exceeds length of the DB field, so URLs are trimmed and become conflicting
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage SQLSTATE[23000]: test: 1062 test
+ */
+ public function testReplaceIfThrewExceptionOnDuplicateEntry()
{
$url = $this->getMock(\Magento\UrlRewrite\Service\V1\Data\UrlRewrite::class, [], [], '', false);
diff --git a/app/code/Magento/UrlRewrite/composer.json b/app/code/Magento/UrlRewrite/composer.json
index 87e033e994159..b848111d30c0a 100644
--- a/app/code/Magento/UrlRewrite/composer.json
+++ b/app/code/Magento/UrlRewrite/composer.json
@@ -3,16 +3,16 @@
"description": "N/A",
"require": {
"php": "7.0.2|7.0.4|~7.0.6|~7.1.0",
- "magento/module-catalog": "101.1.*",
- "magento/module-store": "100.2.*",
- "magento/framework": "100.2.*",
- "magento/module-backend": "100.2.*",
- "magento/module-catalog-url-rewrite": "100.2.*",
- "magento/module-cms": "101.1.*",
- "magento/module-cms-url-rewrite": "100.2.*"
+ "magento/module-catalog": "101.2.*",
+ "magento/module-store": "100.3.*",
+ "magento/framework": "100.3.*",
+ "magento/module-backend": "100.3.*",
+ "magento/module-catalog-url-rewrite": "100.3.*",
+ "magento/module-cms": "101.2.*",
+ "magento/module-cms-url-rewrite": "100.3.*"
},
"type": "magento2-module",
- "version": "100.2.0-dev",
+ "version": "100.3.0-dev",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/UrlRewrite/etc/adminhtml/di.xml b/app/code/Magento/UrlRewrite/etc/adminhtml/di.xml
new file mode 100644
index 0000000000000..bee93f0c33837
--- /dev/null
+++ b/app/code/Magento/UrlRewrite/etc/adminhtml/di.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+ \Magento\UrlRewrite\Model\Message\UrlRewriteExceptionMessageFactory
+
+
+
+
+
+
+
+ \Magento\Framework\View\Element\Message\Renderer\BlockRenderer::CODE
+
+ Magento_UrlRewrite::messages/url_duplicate_message.phtml
+
+
+
+
+
+
diff --git a/app/code/Magento/UrlRewrite/i18n/en_US.csv b/app/code/Magento/UrlRewrite/i18n/en_US.csv
index 9b07b52236304..54f97b44acef6 100644
--- a/app/code/Magento/UrlRewrite/i18n/en_US.csv
+++ b/app/code/Magento/UrlRewrite/i18n/en_US.csv
@@ -1,7 +1,7 @@
"Edit URL Rewrite for a Category","Edit URL Rewrite for a Category"
"Add URL Rewrite for a Category","Add URL Rewrite for a Category"
Category:,Category:
-"We can\'t set up a URL rewrite because the product you chose is not associated with a website.","We can\'t set up a URL rewrite because the product you chose is not associated with a website."
+"We can't set up a URL rewrite because the product you chose is not associated with a website.","We can't set up a URL rewrite because the product you chose is not associated with a website."
"Please assign a website to the selected category.","Please assign a website to the selected category."
"Edit URL Rewrite for a Product","Edit URL Rewrite for a Product"
"Add URL Rewrite for a Product","Add URL Rewrite for a Product"
@@ -35,12 +35,12 @@ Store,Store
"URL Rewrite Management","URL Rewrite Management"
"Add URL Rewrite","Add URL Rewrite"
Custom,Custom
-"For category","For category"
-"For product","For product"
+"For Category","For Category"
+"For Product","For Product"
"For CMS page","For CMS page"
-"Create URL Rewrite:","Create URL Rewrite:"
+"Create URL Rewrite","Create URL Rewrite"
"You deleted the URL rewrite.","You deleted the URL rewrite."
-"We can\'t delete URL Rewrite right now.","We can\'t delete URL Rewrite right now."
+"We can't delete URL Rewrite right now.","We can't delete URL Rewrite right now."
"URL Rewrites","URL Rewrites"
"The product you chose is not associated with the selected store or category.","The product you chose is not associated with the selected store or category."
"The category you chose is not associated with the selected store.","The category you chose is not associated with the selected store."
diff --git a/app/code/Magento/UrlRewrite/view/adminhtml/templates/messages/url_duplicate_message.phtml b/app/code/Magento/UrlRewrite/view/adminhtml/templates/messages/url_duplicate_message.phtml
new file mode 100644
index 0000000000000..17e48cb2aab7e
--- /dev/null
+++ b/app/code/Magento/UrlRewrite/view/adminhtml/templates/messages/url_duplicate_message.phtml
@@ -0,0 +1,31 @@
+getData('urls');
+?>
+
+=$block->escapeHtml(__('The value specified in the URL Key field would generate a URL that already exists.')); ?>
+
+
+=$block->escapeHtml(
+ __(
+ 'To resolve this conflict, you can either change the value of the URL Key field '
+ . '(located in the Search Engine Optimization section) to a unique value, or change the Request Path fields'
+ . ' in all locations listed below:'
+ )
+);
+?>
+ $urlTitle) {
+ ?>
+ ='
'; ?>
+
+
diff --git a/app/code/Magento/User/Block/User/Edit.php b/app/code/Magento/User/Block/User/Edit.php
index faf94b28b5966..6fd5f277449f8 100644
--- a/app/code/Magento/User/Block/User/Edit.php
+++ b/app/code/Magento/User/Block/User/Edit.php
@@ -65,13 +65,14 @@ protected function _construct()
]
);
- $deleteConfirmMsg = __("Are you sure you want to revoke the user\'s tokens?");
+ $deleteConfirmMsg = __("Are you sure you want to revoke the user's tokens?");
$this->addButton(
'invalidate',
[
'label' => __('Force Sign-In'),
'class' => 'invalidate-token',
- 'onclick' => "deleteConfirm('" . $deleteConfirmMsg . "', '" . $this->getInvalidateUrl() . "')",
+ 'onclick' => "deleteConfirm('" . $this->escapeJs($this->escapeHtml($deleteConfirmMsg)) .
+ "', '" . $this->getInvalidateUrl() . "')",
]
);
}
diff --git a/app/code/Magento/User/Controller/Adminhtml/Auth/Forgotpassword.php b/app/code/Magento/User/Controller/Adminhtml/Auth/Forgotpassword.php
index 336b6eaba2f08..cd4c3d6950685 100644
--- a/app/code/Magento/User/Controller/Adminhtml/Auth/Forgotpassword.php
+++ b/app/code/Magento/User/Controller/Adminhtml/Auth/Forgotpassword.php
@@ -44,7 +44,7 @@ public function execute()
$resultRedirect = $this->resultRedirectFactory->create();
if (!empty($email) && !empty($params)) {
// Validate received data to be an email address
- if (\Zend_Validate::is($email, 'EmailAddress')) {
+ if (\Zend_Validate::is($email, \Magento\Framework\Validator\EmailAddress::class)) {
try {
$this->securityManager->performSecurityCheck(
\Magento\Security\Model\PasswordResetRequestEvent::ADMIN_PASSWORD_RESET_REQUEST,
diff --git a/app/code/Magento/User/composer.json b/app/code/Magento/User/composer.json
index 38e4061250c9a..d2a5faf4b2955 100644
--- a/app/code/Magento/User/composer.json
+++ b/app/code/Magento/User/composer.json
@@ -3,16 +3,16 @@
"description": "N/A",
"require": {
"php": "7.0.2|7.0.4|~7.0.6|~7.1.0",
- "magento/module-store": "100.2.*",
- "magento/module-authorization": "100.2.*",
- "magento/module-backend": "100.2.*",
- "magento/module-security": "100.2.*",
- "magento/module-integration": "100.2.*",
- "magento/module-email": "100.2.*",
- "magento/framework": "100.2.*"
+ "magento/module-store": "100.3.*",
+ "magento/module-authorization": "100.3.*",
+ "magento/module-backend": "100.3.*",
+ "magento/module-security": "100.3.*",
+ "magento/module-integration": "100.3.*",
+ "magento/module-email": "100.3.*",
+ "magento/framework": "100.3.*"
},
"type": "magento2-module",
- "version": "100.2.0-dev",
+ "version": "100.3.0-dev",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/User/i18n/en_US.csv b/app/code/Magento/User/i18n/en_US.csv
index 215e458d6e28c..064b6428387fe 100644
--- a/app/code/Magento/User/i18n/en_US.csv
+++ b/app/code/Magento/User/i18n/en_US.csv
@@ -24,7 +24,7 @@ Inactive,Inactive
Users,Users
"Save User","Save User"
"Delete User","Delete User"
-"Are you sure you want to revoke the user\'s tokens?","Are you sure you want to revoke the user\'s tokens?"
+"Are you sure you want to revoke the user's tokens?","Are you sure you want to revoke the user's tokens?"
"Force Sign-In","Force Sign-In"
"Edit User '%1'","Edit User '%1'"
"New User","New User"
@@ -45,7 +45,8 @@ Role,Role
"Please correct the password reset token.","Please correct the password reset token."
"Please specify the correct account and try again.","Please specify the correct account and try again."
"Your password reset link has expired.","Your password reset link has expired."
-"We\'ll email you a link to reset your password.","We\'ll email you a link to reset your password."
+"We're unable to send the password reset email.","We're unable to send the password reset email."
+"We'll email you a link to reset your password.","We'll email you a link to reset your password."
"Please correct this email address:","Please correct this email address:"
"Please enter an email address.","Please enter an email address."
"You updated your password.","You updated your password."
@@ -54,12 +55,13 @@ Role,Role
System,System
Permissions,Permissions
"You cannot delete your own account.","You cannot delete your own account."
+"You have entered an invalid password for current user.","You have entered an invalid password for current user."
"You deleted the user.","You deleted the user."
-"We can\'t find a user to delete.","We can\'t find a user to delete."
+"We can't find a user to delete.","We can't find a user to delete."
"This user no longer exists.","This user no longer exists."
"Edit User","Edit User"
-"You have revoked the user\'s tokens.","You have revoked the user\'s tokens."
-"We can\'t find a user to revoke.","We can\'t find a user to revoke."
+"You have revoked the user's tokens.","You have revoked the user's tokens."
+"We can't find a user to revoke.","We can't find a user to revoke."
"You cannot delete self-assigned roles.","You cannot delete self-assigned roles."
"You deleted the role.","You deleted the role."
"An error occurred while deleting this role.","An error occurred while deleting this role."
@@ -67,7 +69,6 @@ Permissions,Permissions
"New Role","New Role"
"This role no longer exists.","This role no longer exists."
"You saved the role.","You saved the role."
-"You have entered an invalid password for current user.","You have entered an invalid password for current user."
"An error occurred while saving this role.","An error occurred while saving this role."
"You saved the user.","You saved the user."
"A user with the same user name or email already exists.","A user with the same user name or email already exists."
@@ -88,8 +89,8 @@ username,username
"Your password must be at least %1 characters.","Your password must be at least %1 characters."
"Your password must include both numeric and alphabetic characters.","Your password must include both numeric and alphabetic characters."
"Your password confirmation must match your password.","Your password confirmation must match your password."
-"It\'s time to change your password.","It\'s time to change your password."
-"It\'s time to change your password.","It\'s time to change your password."
+"It's time to change your password.","It's time to change your password."
+"It's time to change your password.","It's time to change your password."
"Your password has expired; please contact your administrator.","Your password has expired; please contact your administrator."
"Password Help","Password Help"
"Enter your email address. You will receive an email with a link to reset your password.","Enter your email address. You will receive an email with a link to reset your password."
@@ -107,11 +108,13 @@ All,All
Resources,Resources
"Warning!\r\nThis action will remove this user from already assigned role\r\nAre you sure?","Warning!\r\nThis action will remove this user from already assigned role\r\nAre you sure?"
"Warning!\r\nThis action will remove those users from already assigned roles\r\nAre you sure?","Warning!\r\nThis action will remove those users from already assigned roles\r\nAre you sure?"
+"Password Reset Confirmation for %name","Password Reset Confirmation for %name"
"%name,","%name,"
"There was recently a request to change the password for your account.","There was recently a request to change the password for your account."
"If you requested this change, reset your password here:","If you requested this change, reset your password here:"
"If you did not make this request, you can ignore this email and your password will remain the same.","If you did not make this request, you can ignore this email and your password will remain the same."
"Thank you,","Thank you,"
+"New %changes for %user_name","New %changes for %user_name"
"Hello,","Hello,"
"We have received a request to change the following information associated with your account at %store_name: %changes.","We have received a request to change the following information associated with your account at %store_name: %changes."
"If you have not authorized this action, please contact us immediately at %store_email","If you have not authorized this action, please contact us immediately at %store_email"
diff --git a/app/code/Magento/User/view/adminhtml/templates/role/info.phtml b/app/code/Magento/User/view/adminhtml/templates/role/info.phtml
index 689b8c82ceeba..69f2627cd563f 100644
--- a/app/code/Magento/User/view/adminhtml/templates/role/info.phtml
+++ b/app/code/Magento/User/view/adminhtml/templates/role/info.phtml
@@ -9,8 +9,8 @@