From 9c2f3c14ab16ebd1864ba3a531f6dd0a7df351e1 Mon Sep 17 00:00:00 2001 From: Joan He Date: Fri, 15 Sep 2017 13:17:15 -0500 Subject: [PATCH 001/194] MAGETWO-80488: Apply AR code from previous development - apply analytics-restore-ce.diff --- .../Analytics/Api/Data/LinkInterface.php | 27 ++ .../Analytics/Api/LinkProviderInterface.php | 19 ++ .../System/Config/AdditionalComment.php | 40 +++ .../System/Config/CollectionTimeLabel.php | 31 ++ .../System/Config/SubscriptionStatusLabel.php | 69 ++++ .../Adminhtml/BIEssentials/SignUp.php | 70 ++++ .../Controller/Adminhtml/Reports/Show.php | 80 +++++ .../Adminhtml/Subscription/Activate.php | 142 ++++++++ .../Adminhtml/Subscription/Postpone.php | 103 ++++++ .../Adminhtml/Subscription/Retry.php | 78 +++++ .../Magento/Analytics/Cron/CollectData.php | 58 ++++ app/code/Magento/Analytics/Cron/SignUp.php | 109 ++++++ app/code/Magento/Analytics/Cron/Update.php | 100 ++++++ app/code/Magento/Analytics/LICENSE.txt | 48 +++ app/code/Magento/Analytics/LICENSE_AFL.txt | 48 +++ .../Analytics/Model/AnalyticsToken.php | 101 ++++++ .../Model/Condition/CanViewNotification.php | 87 +++++ app/code/Magento/Analytics/Model/Config.php | 44 +++ .../Baseurl/SubscriptionUpdateHandler.php | 116 +++++++ .../Model/Config/Backend/CollectionTime.php | 95 ++++++ .../Model/Config/Backend/Enabled.php | 88 +++++ .../Backend/Enabled/SubscriptionHandler.php | 198 +++++++++++ .../Model/Config/Backend/Vertical.php | 34 ++ .../Magento/Analytics/Model/Config/Mapper.php | 68 ++++ .../Magento/Analytics/Model/Config/Reader.php | 57 ++++ .../Model/Config/Source/Vertical.php | 55 +++ .../Analytics/Model/ConfigInterface.php | 24 ++ .../Magento/Analytics/Model/Connector.php | 69 ++++ .../Model/Connector/CommandInterface.php | 23 ++ .../Model/Connector/Http/Client/Curl.php | 117 +++++++ .../Model/Connector/Http/ClientInterface.php | 31 ++ .../Connector/Http/ConverterInterface.php | 35 ++ .../Model/Connector/Http/JsonConverter.php | 50 +++ .../Model/Connector/Http/ResponseFactory.php | 25 ++ .../Http/ResponseHandlerInterface.php | 20 ++ .../Model/Connector/Http/ResponseResolver.php | 53 +++ .../Connector/NotifyDataChangedCommand.php | 102 ++++++ .../Analytics/Model/Connector/OTPRequest.php | 124 +++++++ .../Model/Connector/ResponseHandler/OTP.php | 26 ++ .../Connector/ResponseHandler/ReSignUp.php | 65 ++++ .../Connector/ResponseHandler/SignUp.php | 56 +++ .../Connector/ResponseHandler/Update.php | 26 ++ .../Model/Connector/SignUpCommand.php | 134 ++++++++ .../Model/Connector/UpdateCommand.php | 124 +++++++ .../Magento/Analytics/Model/Cryptographer.php | 140 ++++++++ .../Analytics/Model/EncodedContext.php | 58 ++++ .../State/SubscriptionUpdateException.php | 18 + .../Analytics/Model/ExportDataHandler.php | 219 ++++++++++++ .../Model/ExportDataHandlerInterface.php | 21 ++ .../Model/ExportDataHandlerNotification.php | 52 +++ app/code/Magento/Analytics/Model/FileInfo.php | 58 ++++ .../Analytics/Model/FileInfoManager.php | 133 ++++++++ .../Magento/Analytics/Model/FileRecorder.php | 147 ++++++++ .../Analytics/Model/IntegrationManager.php | 135 ++++++++ app/code/Magento/Analytics/Model/Link.php | 60 ++++ .../Magento/Analytics/Model/LinkProvider.php | 95 ++++++ .../Analytics/Model/NotificationTime.php | 72 ++++ .../Model/Plugin/BaseUrlConfigPlugin.php | 66 ++++ .../Analytics/Model/ProviderFactory.php | 43 +++ .../Analytics/Model/ReportUrlProvider.php | 102 ++++++ .../Magento/Analytics/Model/ReportWriter.php | 108 ++++++ .../Analytics/Model/ReportWriterInterface.php | 30 ++ .../Model/ReportXml/ModuleIterator.php | 52 +++ .../Model/StoreConfigurationProvider.php | 109 ++++++ .../Model/SubscriptionStatusProvider.php | 128 +++++++ .../NotificationAboutFailedSubscription.php | 88 +++++ app/code/Magento/Analytics/README.md | 25 ++ .../Magento/Analytics/ReportXml/Config.php | 47 +++ .../ReportXml/Config/Converter/Xml.php | 64 ++++ .../Analytics/ReportXml/Config/Mapper.php | 39 +++ .../Analytics/ReportXml/Config/Reader.php | 62 ++++ .../Analytics/ReportXml/ConfigInterface.php | 25 ++ .../Analytics/ReportXml/ConnectionFactory.php | 70 ++++ .../DB/Assembler/AssemblerInterface.php | 29 ++ .../DB/Assembler/FilterAssembler.php | 69 ++++ .../ReportXml/DB/Assembler/FromAssembler.php | 75 +++++ .../ReportXml/DB/Assembler/JoinAssembler.php | 120 +++++++ .../ReportXml/DB/ColumnsResolver.php | 107 ++++++ .../ReportXml/DB/ConditionResolver.php | 175 ++++++++++ .../Analytics/ReportXml/DB/NameResolver.php | 43 +++ .../ReportXml/DB/ReportValidator.php | 69 ++++ .../Analytics/ReportXml/DB/SelectBuilder.php | 318 ++++++++++++++++++ .../ReportXml/DB/SelectBuilderFactory.php | 47 +++ .../Analytics/ReportXml/IteratorFactory.php | 66 ++++ .../Magento/Analytics/ReportXml/Query.php | 105 ++++++ .../Analytics/ReportXml/QueryFactory.php | 153 +++++++++ .../Analytics/ReportXml/ReportProvider.php | 83 +++++ .../Analytics/ReportXml/SelectHydrator.php | 153 +++++++++ .../Magento/Analytics/Setup/InstallData.php | 47 +++ .../System/Config/AdditionalCommentTest.php | 76 +++++ .../System/Config/CollectionTimeLabelTest.php | 79 +++++ .../Config/SubscriptionStatusLabelTest.php | 86 +++++ .../Adminhtml/BIEssentials/SignUpTest.php | 84 +++++ .../Controller/Adminhtml/Reports/ShowTest.php | 185 ++++++++++ .../Adminhtml/Subscription/ActivateTest.php | 252 ++++++++++++++ .../Adminhtml/Subscription/PostponeTest.php | 168 +++++++++ .../Adminhtml/Subscription/RetryTest.php | 159 +++++++++ .../Test/Unit/Cron/CollectDataTest.php | 91 +++++ .../Analytics/Test/Unit/Cron/SignUpTest.php | 133 ++++++++ .../Analytics/Test/Unit/Cron/UpdateTest.php | 214 ++++++++++++ .../Test/Unit/Model/AnalyticsTokenTest.php | 129 +++++++ .../Condition/CanViewNotificationTest.php | 81 +++++ .../Baseurl/SubscriptionUpdateHandlerTest.php | 178 ++++++++++ .../Config/Backend/CollectionTimeTest.php | 111 ++++++ .../Enabled/SubscriptionHandlerTest.php | 185 ++++++++++ .../Unit/Model/Config/Backend/EnabledTest.php | 184 ++++++++++ .../Model/Config/Backend/VerticalTest.php | 59 ++++ .../Test/Unit/Model/Config/MapperTest.php | 142 ++++++++ .../Test/Unit/Model/Config/ReaderTest.php | 108 ++++++ .../Unit/Model/Config/Source/VerticalTest.php | 60 ++++ .../Analytics/Test/Unit/Model/ConfigTest.php | 68 ++++ .../Model/Connector/Http/Client/CurlTest.php | 218 ++++++++++++ .../Connector/Http/JsonConverterTest.php | 34 ++ .../Connector/Http/ResponseResolverTest.php | 39 +++ .../NotifyDataChangedCommandTest.php | 107 ++++++ .../Unit/Model/Connector/OTPRequestTest.php | 187 ++++++++++ .../Connector/ResponseHandler/OTPTest.php | 22 ++ .../ResponseHandler/ReSignUpTest.php | 36 ++ .../Connector/ResponseHandler/SignUpTest.php | 30 ++ .../Connector/ResponseHandler/UpdateTest.php | 20 ++ .../Model/Connector/SignUpCommandTest.php | 174 ++++++++++ .../Model/Connector/UpdateCommandTest.php | 143 ++++++++ .../Test/Unit/Model/ConnectorTest.php | 70 ++++ .../Test/Unit/Model/CryptographerTest.php | 226 +++++++++++++ .../Test/Unit/Model/EncodedContextTest.php | 61 ++++ .../ExportDataHandlerNotificationTest.php | 74 ++++ .../Test/Unit/Model/ExportDataHandlerTest.php | 270 +++++++++++++++ .../Test/Unit/Model/FileInfoManagerTest.php | 194 +++++++++++ .../Test/Unit/Model/FileInfoTest.php | 62 ++++ .../Test/Unit/Model/FileRecorderTest.php | 209 ++++++++++++ .../Unit/Model/IntegrationManagerTest.php | 228 +++++++++++++ .../Test/Unit/Model/LinkProviderTest.php | 166 +++++++++ .../Test/Unit/Model/NotificationTimeTest.php | 76 +++++ .../Model/Plugin/BaseUrlConfigPluginTest.php | 147 ++++++++ .../Test/Unit/Model/ReportUrlProviderTest.php | 153 +++++++++ .../Test/Unit/Model/ReportWriterTest.php | 213 ++++++++++++ .../Model/ReportXml/ModuleIteratorTest.php | 50 +++ .../Model/StoreConfigurationProviderTest.php | 123 +++++++ .../Model/SubscriptionStatusProviderTest.php | 196 +++++++++++ ...otificationAboutFailedSubscriptionTest.php | 106 ++++++ .../ReportXml/Config/Converter/XmlTest.php | 121 +++++++ .../Test/Unit/ReportXml/Config/MapperTest.php | 47 +++ .../ReportXml/Config/_files/valid_reports.xml | 25 ++ .../Test/Unit/ReportXml/ConfigTest.php | 64 ++++ .../Unit/ReportXml/ConnectionFactoryTest.php | 106 ++++++ .../DB/Assembler/FilterAssemblerTest.php | 143 ++++++++ .../DB/Assembler/FromAssemblerTest.php | 167 +++++++++ .../DB/Assembler/JoinAssemblerTest.php | 279 +++++++++++++++ .../Unit/ReportXml/DB/ColumnsResolverTest.php | 150 +++++++++ .../ReportXml/DB/ConditionResolverTest.php | 108 ++++++ .../Unit/ReportXml/DB/NameResolverTest.php | 90 +++++ .../Unit/ReportXml/DB/ReportValidatorTest.php | 125 +++++++ .../Unit/ReportXml/DB/SelectBuilderTest.php | 103 ++++++ .../Unit/ReportXml/IteratorFactoryTest.php | 59 ++++ .../Test/Unit/ReportXml/QueryFactoryTest.php | 239 +++++++++++++ .../Test/Unit/ReportXml/QueryTest.php | 90 +++++ .../Unit/ReportXml/ReportProviderTest.php | 180 ++++++++++ .../Unit/ReportXml/SelectHydratorTest.php | 257 ++++++++++++++ .../Ui/DataProvider/DummyDataProviderTest.php | 228 +++++++++++++ .../Ui/DataProvider/DummyDataProvider.php | 259 ++++++++++++++ app/code/Magento/Analytics/composer.json | 26 ++ .../Analytics/docs/images/M2_MA_signup.png | Bin 0 -> 11422 bytes .../docs/images/analytics_modules.png | Bin 0 -> 6845 bytes .../Analytics/docs/images/data_transition.png | Bin 0 -> 16397 bytes .../Analytics/docs/images/definition.png | Bin 0 -> 7138 bytes .../docs/images/mbi_file_exchange.png | Bin 0 -> 19199 bytes .../Magento/Analytics/docs/images/signup.png | Bin 0 -> 7289 bytes .../Magento/Analytics/docs/images/update.png | Bin 0 -> 7534 bytes .../Analytics/docs/images/update_request.png | Bin 0 -> 13059 bytes app/code/Magento/Analytics/etc/acl.xml | 31 ++ .../Magento/Analytics/etc/adminhtml/di.xml | 16 + .../Magento/Analytics/etc/adminhtml/menu.xml | 19 ++ .../Analytics/etc/adminhtml/routes.xml | 14 + .../Analytics/etc/adminhtml/system.xml | 47 +++ app/code/Magento/Analytics/etc/analytics.xml | 50 +++ app/code/Magento/Analytics/etc/analytics.xsd | 80 +++++ app/code/Magento/Analytics/etc/config.xml | 25 ++ app/code/Magento/Analytics/etc/crontab.xml | 14 + app/code/Magento/Analytics/etc/di.xml | 262 +++++++++++++++ app/code/Magento/Analytics/etc/module.xml | 17 + app/code/Magento/Analytics/etc/reports.xml | 48 +++ app/code/Magento/Analytics/etc/reports.xsd | 88 +++++ app/code/Magento/Analytics/etc/webapi.xml | 16 + app/code/Magento/Analytics/i18n/en_US.csv | 103 ++++++ app/code/Magento/Analytics/registration.php | 11 + .../layout/adminhtml_dashboard_index.xml | 21 ++ .../templates/dashboard/section.phtml | 28 ++ .../analytics_subscription_form.xml | 247 ++++++++++++++ .../adminhtml/web/js/modal/modal-component.js | 66 ++++ .../web/template/buttons-container.html | 13 + .../form/components/single/checkbox.html | 17 + app/code/Magento/CatalogAnalytics/LICENSE.txt | 48 +++ .../Magento/CatalogAnalytics/LICENSE_AFL.txt | 48 +++ app/code/Magento/CatalogAnalytics/README.md | 3 + .../Magento/CatalogAnalytics/composer.json | 23 ++ .../CatalogAnalytics/etc/analytics.xml | 18 + .../Magento/CatalogAnalytics/etc/module.xml | 15 + .../Magento/CatalogAnalytics/etc/reports.xml | 15 + .../Magento/CatalogAnalytics/registration.php | 11 + .../Magento/CustomerAnalytics/LICENSE.txt | 48 +++ .../Magento/CustomerAnalytics/LICENSE_AFL.txt | 48 +++ app/code/Magento/CustomerAnalytics/README.md | 3 + .../Magento/CustomerAnalytics/composer.json | 23 ++ .../CustomerAnalytics/etc/analytics.xml | 18 + .../Magento/CustomerAnalytics/etc/module.xml | 15 + .../Magento/CustomerAnalytics/etc/reports.xml | 17 + .../CustomerAnalytics/registration.php | 11 + app/code/Magento/QuoteAnalytics/LICENSE.txt | 48 +++ .../Magento/QuoteAnalytics/LICENSE_AFL.txt | 48 +++ app/code/Magento/QuoteAnalytics/README.md | 3 + app/code/Magento/QuoteAnalytics/composer.json | 23 ++ .../Magento/QuoteAnalytics/etc/analytics.xml | 18 + .../Magento/QuoteAnalytics/etc/module.xml | 15 + .../Magento/QuoteAnalytics/etc/reports.xml | 22 ++ .../Magento/QuoteAnalytics/registration.php | 11 + app/code/Magento/ReviewAnalytics/LICENSE.txt | 48 +++ .../Magento/ReviewAnalytics/LICENSE_AFL.txt | 48 +++ app/code/Magento/ReviewAnalytics/README.md | 3 + .../Magento/ReviewAnalytics/composer.json | 23 ++ .../Magento/ReviewAnalytics/etc/analytics.xml | 27 ++ .../Magento/ReviewAnalytics/etc/module.xml | 15 + .../Magento/ReviewAnalytics/etc/reports.xml | 25 ++ .../Magento/ReviewAnalytics/registration.php | 11 + app/code/Magento/SalesAnalytics/LICENSE.txt | 48 +++ .../Magento/SalesAnalytics/LICENSE_AFL.txt | 48 +++ app/code/Magento/SalesAnalytics/README.md | 3 + app/code/Magento/SalesAnalytics/composer.json | 23 ++ .../Magento/SalesAnalytics/etc/analytics.xml | 36 ++ .../Magento/SalesAnalytics/etc/module.xml | 15 + .../Magento/SalesAnalytics/etc/reports.xml | 55 +++ .../Magento/SalesAnalytics/registration.php | 11 + .../Magento/WishlistAnalytics/LICENSE.txt | 48 +++ .../Magento/WishlistAnalytics/LICENSE_AFL.txt | 48 +++ app/code/Magento/WishlistAnalytics/README.md | 3 + .../Magento/WishlistAnalytics/composer.json | 23 ++ .../WishlistAnalytics/etc/analytics.xml | 27 ++ .../Magento/WishlistAnalytics/etc/module.xml | 15 + .../Magento/WishlistAnalytics/etc/reports.xml | 25 ++ .../WishlistAnalytics/registration.php | 11 + composer.json | 7 + .../Analytics/Api/LinkProviderTest.php | 100 ++++++ .../Mtf/App/State/NotificationTimeHandler.php | 55 +++ .../AdvancedReporting/ReportsSectionBlock.php | 31 ++ .../AdvancedReporting/SubscriptionBlock.php | 99 ++++++ .../Block/System/Config/AnalyticsForm.php | 158 +++++++++ .../AssertAdvancedReportingPage.php | 53 +++ .../Constraint/AssertBIEssentialsLink.php | 87 +++++ .../AssertConfigAnalyticsDisabled.php | 49 +++ .../AssertConfigAnalyticsEnabled.php | 50 +++ .../AssertConfigAnalyticsRestored.php | 54 +++ ...ssertConfigAnalyticsSendingTimeAndZone.php | 52 +++ .../AssertConfigAnalyticsVerticalScope.php | 39 +++ .../AssertDisableReportingInPopup.php | 49 +++ .../AssertEmptyVerticalCanNotBeSaved.php | 42 +++ .../AssertEnableReportingInPopup.php | 42 +++ .../Constraint/AssertSkipReportingInPopup.php | 42 +++ .../AssertSubscriptionPopupNotExist.php | 39 +++ .../Test/Constraint/AssertVerticalIsSet.php | 42 +++ .../Test/Page/Adminhtml/ConfigAnalytics.xml | 13 + .../Test/Page/Adminhtml/Dashboard.xml | 14 + .../Test/Repository/DefaultTimeZone.xml | 35 ++ .../Analytics/Test/Repository/Integration.xml | 16 + .../Analytics/Test/Repository/Role.xml | 19 ++ .../Analytics/Test/Repository/User.xml | 24 ++ .../TestCase/AdvancedReportingButtonTest.php | 36 ++ .../TestCase/AdvancedReportingButtonTest.xml | 15 + ...lyticsSubscriptionCheckPermissionsTest.php | 37 ++ ...lyticsSubscriptionCheckPermissionsTest.xml | 15 + .../Test/TestCase/EnableDisableTest.php | 42 +++ .../Test/TestCase/EnableDisableTest.xml | 21 ++ .../Analytics/Test/TestCase/InstallTest.xml | 28 ++ .../Test/TestCase/NavigateMenuTest.xml | 23 ++ .../Test/TestCase/SetTimeToSendDataTest.php | 75 +++++ .../Test/TestCase/SetTimeToSendDataTest.xml | 18 + .../Test/TestCase/SetVerticalTest.php | 40 +++ .../Test/TestCase/SetVerticalTest.xml | 21 ++ .../Test/TestStep/OpenAnalyticsConfigStep.php | 54 +++ .../app/Magento/Analytics/Test/etc/di.xml | 51 +++ .../Magento/Analytics/Test/etc/testcase.xml | 14 + .../Setup/Test/TestCase/UpgradeSystemTest.php | 26 +- .../InjectableTests/travis_acceptance_1.xml | 1 + .../Http/ReSignUpResponseResolverTest.php | 177 ++++++++++ .../Model/Plugin/BaseUrlConfigPluginTest.php | 207 ++++++++++++ .../Analytics/Model/ReportUrlProviderTest.php | 56 +++ .../Magento/Analytics/_files/create_link.php | 21 ++ ...nabled_subscription_with_invalid_token.php | 29 ++ ...bscription_with_invalid_token_rollback.php | 29 ++ .../js/modal/modal-component.test.js | 126 +++++++ 288 files changed, 21119 insertions(+), 4 deletions(-) create mode 100644 app/code/Magento/Analytics/Api/Data/LinkInterface.php create mode 100644 app/code/Magento/Analytics/Api/LinkProviderInterface.php create mode 100644 app/code/Magento/Analytics/Block/Adminhtml/System/Config/AdditionalComment.php create mode 100644 app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php create mode 100644 app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php create mode 100644 app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php create mode 100644 app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php create mode 100644 app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php create mode 100644 app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php create mode 100644 app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php create mode 100644 app/code/Magento/Analytics/Cron/CollectData.php create mode 100644 app/code/Magento/Analytics/Cron/SignUp.php create mode 100644 app/code/Magento/Analytics/Cron/Update.php create mode 100644 app/code/Magento/Analytics/LICENSE.txt create mode 100644 app/code/Magento/Analytics/LICENSE_AFL.txt create mode 100644 app/code/Magento/Analytics/Model/AnalyticsToken.php create mode 100644 app/code/Magento/Analytics/Model/Condition/CanViewNotification.php create mode 100644 app/code/Magento/Analytics/Model/Config.php create mode 100644 app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php create mode 100644 app/code/Magento/Analytics/Model/Config/Backend/CollectionTime.php create mode 100644 app/code/Magento/Analytics/Model/Config/Backend/Enabled.php create mode 100644 app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php create mode 100644 app/code/Magento/Analytics/Model/Config/Backend/Vertical.php create mode 100644 app/code/Magento/Analytics/Model/Config/Mapper.php create mode 100644 app/code/Magento/Analytics/Model/Config/Reader.php create mode 100644 app/code/Magento/Analytics/Model/Config/Source/Vertical.php create mode 100644 app/code/Magento/Analytics/Model/ConfigInterface.php create mode 100644 app/code/Magento/Analytics/Model/Connector.php create mode 100644 app/code/Magento/Analytics/Model/Connector/CommandInterface.php create mode 100644 app/code/Magento/Analytics/Model/Connector/Http/Client/Curl.php create mode 100644 app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php create mode 100644 app/code/Magento/Analytics/Model/Connector/Http/ConverterInterface.php create mode 100644 app/code/Magento/Analytics/Model/Connector/Http/JsonConverter.php create mode 100644 app/code/Magento/Analytics/Model/Connector/Http/ResponseFactory.php create mode 100644 app/code/Magento/Analytics/Model/Connector/Http/ResponseHandlerInterface.php create mode 100644 app/code/Magento/Analytics/Model/Connector/Http/ResponseResolver.php create mode 100644 app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php create mode 100644 app/code/Magento/Analytics/Model/Connector/OTPRequest.php create mode 100644 app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php create mode 100644 app/code/Magento/Analytics/Model/Connector/ResponseHandler/ReSignUp.php create mode 100644 app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php create mode 100644 app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php create mode 100644 app/code/Magento/Analytics/Model/Connector/SignUpCommand.php create mode 100644 app/code/Magento/Analytics/Model/Connector/UpdateCommand.php create mode 100644 app/code/Magento/Analytics/Model/Cryptographer.php create mode 100644 app/code/Magento/Analytics/Model/EncodedContext.php create mode 100644 app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php create mode 100644 app/code/Magento/Analytics/Model/ExportDataHandler.php create mode 100644 app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php create mode 100644 app/code/Magento/Analytics/Model/ExportDataHandlerNotification.php create mode 100644 app/code/Magento/Analytics/Model/FileInfo.php create mode 100644 app/code/Magento/Analytics/Model/FileInfoManager.php create mode 100644 app/code/Magento/Analytics/Model/FileRecorder.php create mode 100644 app/code/Magento/Analytics/Model/IntegrationManager.php create mode 100644 app/code/Magento/Analytics/Model/Link.php create mode 100644 app/code/Magento/Analytics/Model/LinkProvider.php create mode 100644 app/code/Magento/Analytics/Model/NotificationTime.php create mode 100644 app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php create mode 100644 app/code/Magento/Analytics/Model/ProviderFactory.php create mode 100644 app/code/Magento/Analytics/Model/ReportUrlProvider.php create mode 100644 app/code/Magento/Analytics/Model/ReportWriter.php create mode 100644 app/code/Magento/Analytics/Model/ReportWriterInterface.php create mode 100644 app/code/Magento/Analytics/Model/ReportXml/ModuleIterator.php create mode 100644 app/code/Magento/Analytics/Model/StoreConfigurationProvider.php create mode 100644 app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php create mode 100644 app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php create mode 100644 app/code/Magento/Analytics/README.md create mode 100644 app/code/Magento/Analytics/ReportXml/Config.php create mode 100644 app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php create mode 100644 app/code/Magento/Analytics/ReportXml/Config/Mapper.php create mode 100644 app/code/Magento/Analytics/ReportXml/Config/Reader.php create mode 100644 app/code/Magento/Analytics/ReportXml/ConfigInterface.php create mode 100644 app/code/Magento/Analytics/ReportXml/ConnectionFactory.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/Assembler/FilterAssembler.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/NameResolver.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php create mode 100644 app/code/Magento/Analytics/ReportXml/IteratorFactory.php create mode 100644 app/code/Magento/Analytics/ReportXml/Query.php create mode 100644 app/code/Magento/Analytics/ReportXml/QueryFactory.php create mode 100644 app/code/Magento/Analytics/ReportXml/ReportProvider.php create mode 100644 app/code/Magento/Analytics/ReportXml/SelectHydrator.php create mode 100644 app/code/Magento/Analytics/Setup/InstallData.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Reports/ShowTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Baseurl/SubscriptionUpdateHandlerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/CollectionTimeTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/Config/_files/valid_reports.xml create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php create mode 100644 app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php create mode 100644 app/code/Magento/Analytics/composer.json create mode 100644 app/code/Magento/Analytics/docs/images/M2_MA_signup.png create mode 100644 app/code/Magento/Analytics/docs/images/analytics_modules.png create mode 100644 app/code/Magento/Analytics/docs/images/data_transition.png create mode 100644 app/code/Magento/Analytics/docs/images/definition.png create mode 100644 app/code/Magento/Analytics/docs/images/mbi_file_exchange.png create mode 100644 app/code/Magento/Analytics/docs/images/signup.png create mode 100644 app/code/Magento/Analytics/docs/images/update.png create mode 100644 app/code/Magento/Analytics/docs/images/update_request.png create mode 100644 app/code/Magento/Analytics/etc/acl.xml create mode 100644 app/code/Magento/Analytics/etc/adminhtml/di.xml create mode 100644 app/code/Magento/Analytics/etc/adminhtml/menu.xml create mode 100644 app/code/Magento/Analytics/etc/adminhtml/routes.xml create mode 100644 app/code/Magento/Analytics/etc/adminhtml/system.xml create mode 100644 app/code/Magento/Analytics/etc/analytics.xml create mode 100644 app/code/Magento/Analytics/etc/analytics.xsd create mode 100644 app/code/Magento/Analytics/etc/config.xml create mode 100644 app/code/Magento/Analytics/etc/crontab.xml create mode 100644 app/code/Magento/Analytics/etc/di.xml create mode 100644 app/code/Magento/Analytics/etc/module.xml create mode 100644 app/code/Magento/Analytics/etc/reports.xml create mode 100644 app/code/Magento/Analytics/etc/reports.xsd create mode 100644 app/code/Magento/Analytics/etc/webapi.xml create mode 100644 app/code/Magento/Analytics/i18n/en_US.csv create mode 100644 app/code/Magento/Analytics/registration.php create mode 100644 app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml create mode 100644 app/code/Magento/Analytics/view/adminhtml/templates/dashboard/section.phtml create mode 100644 app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_form.xml create mode 100644 app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js create mode 100644 app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html create mode 100644 app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html create mode 100644 app/code/Magento/CatalogAnalytics/LICENSE.txt create mode 100644 app/code/Magento/CatalogAnalytics/LICENSE_AFL.txt create mode 100644 app/code/Magento/CatalogAnalytics/README.md create mode 100644 app/code/Magento/CatalogAnalytics/composer.json create mode 100644 app/code/Magento/CatalogAnalytics/etc/analytics.xml create mode 100644 app/code/Magento/CatalogAnalytics/etc/module.xml create mode 100644 app/code/Magento/CatalogAnalytics/etc/reports.xml create mode 100644 app/code/Magento/CatalogAnalytics/registration.php create mode 100644 app/code/Magento/CustomerAnalytics/LICENSE.txt create mode 100644 app/code/Magento/CustomerAnalytics/LICENSE_AFL.txt create mode 100644 app/code/Magento/CustomerAnalytics/README.md create mode 100644 app/code/Magento/CustomerAnalytics/composer.json create mode 100644 app/code/Magento/CustomerAnalytics/etc/analytics.xml create mode 100644 app/code/Magento/CustomerAnalytics/etc/module.xml create mode 100644 app/code/Magento/CustomerAnalytics/etc/reports.xml create mode 100644 app/code/Magento/CustomerAnalytics/registration.php create mode 100644 app/code/Magento/QuoteAnalytics/LICENSE.txt create mode 100644 app/code/Magento/QuoteAnalytics/LICENSE_AFL.txt create mode 100644 app/code/Magento/QuoteAnalytics/README.md create mode 100644 app/code/Magento/QuoteAnalytics/composer.json create mode 100644 app/code/Magento/QuoteAnalytics/etc/analytics.xml create mode 100644 app/code/Magento/QuoteAnalytics/etc/module.xml create mode 100644 app/code/Magento/QuoteAnalytics/etc/reports.xml create mode 100644 app/code/Magento/QuoteAnalytics/registration.php create mode 100644 app/code/Magento/ReviewAnalytics/LICENSE.txt create mode 100644 app/code/Magento/ReviewAnalytics/LICENSE_AFL.txt create mode 100644 app/code/Magento/ReviewAnalytics/README.md create mode 100644 app/code/Magento/ReviewAnalytics/composer.json create mode 100644 app/code/Magento/ReviewAnalytics/etc/analytics.xml create mode 100644 app/code/Magento/ReviewAnalytics/etc/module.xml create mode 100644 app/code/Magento/ReviewAnalytics/etc/reports.xml create mode 100644 app/code/Magento/ReviewAnalytics/registration.php create mode 100644 app/code/Magento/SalesAnalytics/LICENSE.txt create mode 100644 app/code/Magento/SalesAnalytics/LICENSE_AFL.txt create mode 100644 app/code/Magento/SalesAnalytics/README.md create mode 100644 app/code/Magento/SalesAnalytics/composer.json create mode 100644 app/code/Magento/SalesAnalytics/etc/analytics.xml create mode 100644 app/code/Magento/SalesAnalytics/etc/module.xml create mode 100644 app/code/Magento/SalesAnalytics/etc/reports.xml create mode 100644 app/code/Magento/SalesAnalytics/registration.php create mode 100644 app/code/Magento/WishlistAnalytics/LICENSE.txt create mode 100644 app/code/Magento/WishlistAnalytics/LICENSE_AFL.txt create mode 100644 app/code/Magento/WishlistAnalytics/README.md create mode 100644 app/code/Magento/WishlistAnalytics/composer.json create mode 100644 app/code/Magento/WishlistAnalytics/etc/analytics.xml create mode 100644 app/code/Magento/WishlistAnalytics/etc/module.xml create mode 100644 app/code/Magento/WishlistAnalytics/etc/reports.xml create mode 100644 app/code/Magento/WishlistAnalytics/registration.php create mode 100644 dev/tests/api-functional/testsuite/Magento/Analytics/Api/LinkProviderTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/ReportsSectionBlock.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Block/System/Config/AnalyticsForm.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPage.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertBIEssentialsLink.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsSendingTimeAndZone.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/ConfigAnalytics.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/DefaultTimeZone.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Integration.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/User.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NavigateMenuTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/OpenAnalyticsConfigStep.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml create mode 100644 dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Analytics/_files/create_link.php create mode 100644 dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token.php create mode 100644 dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token_rollback.php create mode 100644 dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js diff --git a/app/code/Magento/Analytics/Api/Data/LinkInterface.php b/app/code/Magento/Analytics/Api/Data/LinkInterface.php new file mode 100644 index 0000000000000..f2b1ec579c4ab --- /dev/null +++ b/app/code/Magento/Analytics/Api/Data/LinkInterface.php @@ -0,0 +1,27 @@ +' . $element->getLabel() . ''; + $html .= '
' . $element->getComment() . '
'; + return $this->decorateRowHtml($element, $html); + } + + /** + * @param \Magento\Framework\Data\Form\Element\AbstractElement $element + * @param string $html + * @return string + * @since 2.2.0 + */ + private function decorateRowHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element, $html) + { + return sprintf( + '
%s
', + $element->getHtmlId(), + $html + ); + } +} diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php new file mode 100644 index 0000000000000..9e19a9e6c2388 --- /dev/null +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php @@ -0,0 +1,31 @@ +_localeDate->getConfigTimezone(); + $getLongTimeZoneName = \IntlTimeZone::createTimeZone($timeZoneCode)->getDisplayName(); + $element->setData( + 'comment', + sprintf("%s (%s)", $getLongTimeZoneName, $timeZoneCode) + ); + return parent::render($element); + } +} diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php new file mode 100644 index 0000000000000..bfdee16707618 --- /dev/null +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php @@ -0,0 +1,69 @@ +subscriptionStatusProvider = $labelStatusProvider; + } + + /** + * Add Subscription status to comment + * + * @param \Magento\Framework\Data\Form\Element\AbstractElement $element + * @return string + * @since 2.2.0 + */ + public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) + { + $element->setData( + 'comment', + $this->prepareLabelValue() + ); + return parent::render($element); + } + + /** + * Prepare label for subscription status + * + * @return string + * @since 2.2.0 + */ + private function prepareLabelValue() + { + return __('Subscription status') . ': ' . __($this->subscriptionStatusProvider->getStatus()); + } +} diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php b/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php new file mode 100644 index 0000000000000..4cbfa639d23b4 --- /dev/null +++ b/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php @@ -0,0 +1,70 @@ +config = $config; + parent::__construct($context); + } + + /** + * Check admin permissions for this controller + * + * @return boolean + * @since 2.2.0 + */ + protected function _isAllowed() + { + return $this->_authorization->isAllowed('Magento_Analytics::bi_essentials'); + } + + /** + * Provides link to BI Essentials signup + * + * @return \Magento\Framework\Controller\AbstractResult + * @since 2.2.0 + */ + public function execute() + { + return $this->resultRedirectFactory->create()->setUrl( + $this->config->getValue($this->urlBIEssentialsConfigPath) + ); + } +} diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php b/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php new file mode 100644 index 0000000000000..5fb0085fee43d --- /dev/null +++ b/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php @@ -0,0 +1,80 @@ +reportUrlProvider = $reportUrlProvider; + parent::__construct($context); + } + + /** + * Check admin permissions for this controller. + * + * @return boolean + * @since 2.2.0 + */ + protected function _isAllowed() + { + return $this->_authorization->isAllowed('Magento_Analytics::analytics_settings'); + } + + /** + * Redirect to resource with reports. + * + * @return Redirect $resultRedirect + * @since 2.2.0 + */ + public function execute() + { + /** @var Redirect $resultRedirect */ + $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'); + } catch (\Exception $e) { + $this->getMessageManager()->addExceptionMessage( + $e, + __('Sorry, there has been an error processing your request. Please try again later.') + ); + $resultRedirect->setPath('adminhtml'); + } + + return $resultRedirect; + } +} diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php new file mode 100644 index 0000000000000..59923e82ef46c --- /dev/null +++ b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php @@ -0,0 +1,142 @@ +logger = $logger; + $this->notificationTime = $notificationTime; + $this->configValueResource = $configValueResource; + $this->preparedValueFactory = $preparedValueFactory; + parent::__construct($context); + } + + /** + * Check admin permissions for this controller + * + * @return boolean + * @since 2.2.0 + */ + protected function _isAllowed() + { + return $this->_authorization->isAllowed('Magento_Analytics::analytics_settings'); + } + + /** + * Activate subscription to Magento BI via AJAX. + * + * @return Json + * @since 2.2.0 + */ + public function execute() + { + try { + if ($this->getRequest()->getParam($this->subscriptionApprovedField)) { + $configValue = $this->preparedValueFactory->create( + Enabled::XML_ENABLED_CONFIG_STRUCTURE_PATH, + Enabledisable::ENABLE_VALUE, + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + + $this->configValueResource + ->save($configValue); + } else { + $this->notificationTime->unsetLastTimeNotificationValue(); + } + $responseContent = [ + 'success' => true, + 'error_message' => '', + ]; + } catch (LocalizedException $e) { + $responseContent = [ + 'success' => false, + 'error_message' => $e->getMessage(), + ]; + $this->logger->error($e->getMessage()); + } catch (\Exception $e) { + $responseContent = [ + 'success' => false, + 'error_message' => __( + 'Sorry, there was an error processing your registration request to Magento Analytics. ' + . 'Please try again later.' + ), + ]; + $this->logger->error($e->getMessage()); + } + /** @var Json $resultJson */ + $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON); + return $resultJson->setData($responseContent); + } +} diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php new file mode 100644 index 0000000000000..068416157ae6a --- /dev/null +++ b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php @@ -0,0 +1,103 @@ +dateTimeFactory = $dateTimeFactory; + $this->notificationTime = $notificationTime; + $this->logger = $logger; + parent::__construct($context); + } + + /** + * Check admin permissions for this controller + * + * @return boolean + * @since 2.2.0 + */ + protected function _isAllowed() + { + return $this->_authorization->isAllowed('Magento_Analytics::analytics_settings'); + } + + /** + * Postpones notification about subscription + * + * @return Json + * @since 2.2.0 + */ + public function execute() + { + try { + $dateTime = $this->dateTimeFactory->create(); + $responseContent = [ + 'success' => $this->notificationTime->storeLastTimeNotification($dateTime->getTimestamp()), + 'error_message' => '' + ]; + } catch (LocalizedException $e) { + $this->logger->error($e->getMessage()); + $responseContent = [ + 'success' => false, + 'error_message' => $e->getMessage() + ]; + } catch (\Exception $e) { + $this->logger->error($e->getMessage()); + $responseContent = [ + 'success' => false, + 'error_message' => __('Error occurred during postponement notification') + ]; + } + /** @var Json $resultJson */ + $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON); + return $resultJson->setData($responseContent); + } +} diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php new file mode 100644 index 0000000000000..85d34e83f0c9f --- /dev/null +++ b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php @@ -0,0 +1,78 @@ +subscriptionHandler = $subscriptionHandler; + parent::__construct($context); + } + + /** + * Check admin permissions for this controller + * + * @return boolean + * @since 2.2.0 + */ + protected function _isAllowed() + { + return $this->_authorization->isAllowed('Magento_Analytics::analytics_settings'); + } + + /** + * Retry process of subscription. + * + * @return Redirect + * @since 2.2.0 + */ + public function execute() + { + /** @var Redirect $resultRedirect */ + $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); + try { + $resultRedirect->setPath('adminhtml'); + $this->subscriptionHandler->processEnabled(); + } catch (LocalizedException $e) { + $this->getMessageManager()->addExceptionMessage($e, $e->getMessage()); + } catch (\Exception $e) { + $this->getMessageManager()->addExceptionMessage( + $e, + __('Sorry, there has been an error processing your request. Please try again later.') + ); + } + + return $resultRedirect; + } +} diff --git a/app/code/Magento/Analytics/Cron/CollectData.php b/app/code/Magento/Analytics/Cron/CollectData.php new file mode 100644 index 0000000000000..d11ade9a812ff --- /dev/null +++ b/app/code/Magento/Analytics/Cron/CollectData.php @@ -0,0 +1,58 @@ +exportDataHandler = $exportDataHandler; + $this->subscriptionStatus = $subscriptionStatus; + } + + /** + * @return bool + * @since 2.2.0 + */ + public function execute() + { + if ($this->subscriptionStatus->getStatus() === SubscriptionStatusProvider::ENABLED) { + $this->exportDataHandler->prepareExportData(); + } + + return true; + } +} diff --git a/app/code/Magento/Analytics/Cron/SignUp.php b/app/code/Magento/Analytics/Cron/SignUp.php new file mode 100644 index 0000000000000..cc5c84e93a6d9 --- /dev/null +++ b/app/code/Magento/Analytics/Cron/SignUp.php @@ -0,0 +1,109 @@ +connector = $connector; + $this->configWriter = $configWriter; + $this->flagManager = $flagManager; + $this->reinitableConfig = $reinitableConfig; + } + + /** + * Execute scheduled subscription operation + * In case of failure writes message to notifications inbox + * + * @return bool + * @since 2.2.0 + */ + public function execute() + { + $attemptsCount = $this->flagManager->getFlagData(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + + if (($attemptsCount === null) || ($attemptsCount <= 0)) { + $this->deleteAnalyticsCronExpr(); + $this->flagManager->deleteFlag(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + return false; + } + + $attemptsCount -= 1; + $this->flagManager->saveFlag(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, $attemptsCount); + $signUpResult = $this->connector->execute('signUp'); + if ($signUpResult === false) { + return false; + } + + $this->deleteAnalyticsCronExpr(); + $this->flagManager->deleteFlag(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + return true; + } + + /** + * Delete cron schedule setting into config. + * + * Delete cron schedule setting for subscription handler into config and + * re-initialize config cache to avoid auto-generate new schedule items. + * + * @return bool + * @since 2.2.0 + */ + private function deleteAnalyticsCronExpr() + { + $this->configWriter->delete(SubscriptionHandler::CRON_STRING_PATH); + $this->reinitableConfig->reinit(); + return true; + } +} diff --git a/app/code/Magento/Analytics/Cron/Update.php b/app/code/Magento/Analytics/Cron/Update.php new file mode 100644 index 0000000000000..89a2496e088c1 --- /dev/null +++ b/app/code/Magento/Analytics/Cron/Update.php @@ -0,0 +1,100 @@ +connector = $connector; + $this->configWriter = $configWriter; + $this->reinitableConfig = $reinitableConfig; + $this->flagManager = $flagManager; + $this->analyticsToken = $analyticsToken; + } + + /** + * Execute scheduled update operation + * + * @return bool + * @since 2.2.0 + */ + public function execute() + { + $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(); + } + + return $result; + } +} diff --git a/app/code/Magento/Analytics/LICENSE.txt b/app/code/Magento/Analytics/LICENSE.txt new file mode 100644 index 0000000000000..49525fd99da9c --- /dev/null +++ b/app/code/Magento/Analytics/LICENSE.txt @@ -0,0 +1,48 @@ + +Open Software License ("OSL") v. 3.0 + +This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Open Software License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/Analytics/LICENSE_AFL.txt b/app/code/Magento/Analytics/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/Analytics/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/Analytics/Model/AnalyticsToken.php b/app/code/Magento/Analytics/Model/AnalyticsToken.php new file mode 100644 index 0000000000000..58ef45b4f4279 --- /dev/null +++ b/app/code/Magento/Analytics/Model/AnalyticsToken.php @@ -0,0 +1,101 @@ +reinitableConfig = $reinitableConfig; + $this->config = $config; + $this->configWriter = $configWriter; + } + + /** + * Get Magento BI token value. + * + * @return string|null + * @since 2.2.0 + */ + public function getToken() + { + return $this->config->getValue($this->tokenPath); + } + + /** + * Stores Magento BI token value. + * + * @param string $value + * + * @return bool + * @since 2.2.0 + */ + public function storeToken($value) + { + $this->configWriter->save($this->tokenPath, $value); + $this->reinitableConfig->reinit(); + + return true; + } + + /** + * Check Magento BI token value exist. + * + * @return bool + * @since 2.2.0 + */ + public function isTokenExist() + { + return (bool)$this->getToken(); + } +} diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php new file mode 100644 index 0000000000000..9200361322dc2 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -0,0 +1,87 @@ +notificationTime = $notificationTime; + $this->dateTimeFactory = $dateTimeFactory; + } + + /** + * Validate is notification popup can be shown + * + * @inheritdoc + * @since 2.2.0 + */ + public function isVisible(array $arguments) + { + $lastNotificationTime = $this->notificationTime->getLastTimeNotification(); + if (!$lastNotificationTime) { + return false; + } + $datetime = $this->dateTimeFactory->create(); + return ( + $datetime->getTimestamp() >= $lastNotificationTime + $this->notificationInterval + ); + } + + /** + * @return string + * @since 2.2.0 + */ + public function getName() + { + return self::NAME; + } +} diff --git a/app/code/Magento/Analytics/Model/Config.php b/app/code/Magento/Analytics/Model/Config.php new file mode 100644 index 0000000000000..140d7130260a2 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config.php @@ -0,0 +1,44 @@ +data = $data; + } + + /** + * Get config value by key. + * + * @param string|null $key + * @param string|null $default + * @return array + * @since 2.2.0 + */ + public function get($key = null, $default = null) + { + return $this->data->get($key, $default); + } +} 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..f9fa38fe7f5fb --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php @@ -0,0 +1,116 @@ +analyticsToken = $analyticsToken; + $this->flagManager = $flagManager; + $this->reinitableConfig = $reinitableConfig; + $this->configWriter = $configWriter; + } + + /** + * Activate process of subscription update handling. + * + * @param string $url + * @return bool + * @since 2.2.0 + */ + 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/Config/Backend/CollectionTime.php b/app/code/Magento/Analytics/Model/Config/Backend/CollectionTime.php new file mode 100644 index 0000000000000..beb6f9d79f7ab --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Backend/CollectionTime.php @@ -0,0 +1,95 @@ +configWriter = $configWriter; + parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data); + } + + /** + * {@inheritdoc} + * + * {@inheritdoc}. Set schedule setting for cron. + * + * @return Value + * @since 2.2.0 + */ + public function afterSave() + { + $result = preg_match('#(?\d{2}),(?\d{2}),(?\d{2})#', $this->getValue(), $time); + + if (!$result) { + throw new LocalizedException(__('Time value has an unsupported format')); + } + + $cronExprArray = [ + $time['min'], # Minute + $time['hour'], # Hour + '*', # Day of the Month + '*', # Month of the Year + '*', # Day of the Week + ]; + + $cronExprString = join(' ', $cronExprArray); + + try { + $this->configWriter->save(self::CRON_SCHEDULE_PATH, $cronExprString); + } catch (\Exception $e) { + $this->_logger->error($e->getMessage()); + throw new LocalizedException(__('Cron settings can\'t be saved')); + } + + return parent::afterSave(); + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php b/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php new file mode 100644 index 0000000000000..5544cd0df9454 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php @@ -0,0 +1,88 @@ +subscriptionHandler = $subscriptionHandler; + parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data); + } + + /** + * Add additional handling after config value was saved. + * + * @return Value + * @throws LocalizedException + * @since 2.2.0 + */ + public function afterSave() + { + try { + if ($this->isValueChanged()) { + $enabled = $this->getData('value'); + + if ($enabled) { + $this->subscriptionHandler->processEnabled(); + } else { + $this->subscriptionHandler->processDisabled(); + } + } + } catch (\Exception $e) { + $this->_logger->error($e->getMessage()); + throw new LocalizedException(__('There was an error save new configuration value.')); + } + + return parent::afterSave(); + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php new file mode 100644 index 0000000000000..95caceddebc88 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php @@ -0,0 +1,198 @@ +configWriter = $configWriter; + $this->flagManager = $flagManager; + $this->analyticsToken = $analyticsToken; + $this->notificationTime = $notificationTime; + $this->reinitableConfig = $reinitableConfig; + } + + /** + * Processing of activation MBI subscription. + * + * Activate process of subscription handling if Analytics token is not received. + * + * @return bool + * @since 2.2.0 + */ + public function processEnabled() + { + if (!$this->analyticsToken->isTokenExist()) { + $this->setCronSchedule(); + $this->setAttemptsFlag(); + $this->notificationTime->unsetLastTimeNotificationValue(); + $this->reinitableConfig->reinit(); + } + + return true; + } + + /** + * Set cron schedule setting into config for activation of subscription process. + * + * @return bool + * @since 2.2.0 + */ + private function setCronSchedule() + { + $cronExprArray = [ + '0', # Minute + '*', # Hour + '*', # Day of the Month + '*', # Month of the Year + '*', # Day of the Week + ]; + + $cronExprString = join(' ', $cronExprArray); + + $this->configWriter->save(self::CRON_STRING_PATH, $cronExprString); + + return true; + } + + /** + * Set flag as reserve counter of attempts subscription operation. + * + * @return bool + * @since 2.2.0 + */ + private function setAttemptsFlag() + { + return $this->flagManager + ->saveFlag(self::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, $this->attemptsInitValue); + } + + /** + * Processing of deactivation MBI subscription. + * + * Disable data collection + * and interrupt subscription handling if Analytics token is not received. + * + * @return bool + * @since 2.2.0 + */ + public function processDisabled() + { + $this->disableCollectionData(); + + if (!$this->analyticsToken->isTokenExist()) { + $this->unsetAttemptsFlag(); + } + + return true; + } + + /** + * Unset flag of attempts subscription operation. + * + * @return bool + * @since 2.2.0 + */ + private function unsetAttemptsFlag() + { + return $this->flagManager + ->deleteFlag(self::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + } + + /** + * Unset schedule of collection data cron. + * + * @return bool + * @since 2.2.0 + */ + private function disableCollectionData() + { + $this->configWriter->delete(CollectionTime::CRON_SCHEDULE_PATH); + + return true; + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Vertical.php b/app/code/Magento/Analytics/Model/Config/Backend/Vertical.php new file mode 100644 index 0000000000000..0fe9caa4ea0a0 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Backend/Vertical.php @@ -0,0 +1,34 @@ +getValue())) { + throw new LocalizedException(__('Please select a vertical.')); + } + + return $this; + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Mapper.php b/app/code/Magento/Analytics/Model/Config/Mapper.php new file mode 100644 index 0000000000000..d672248777ec5 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Mapper.php @@ -0,0 +1,68 @@ + [ + * 'name' => 'file_name', + * 'providers' => [ + * 'reportProvider' => [ + * 'name' => 'report_provider_name', + * 'class' => 'Magento\Analytics\ReportXml\ReportProvider', + * 'parameters' =>[ + * 'name' => 'report_name', + * ], + * ], + * 'customProvider' => [ + * 'name' => 'custom_provider_name', + * 'class' => 'Magento\Analytics\Model\CustomProvider', + * ], + * ], + * ] + * ]; + * @since 2.2.0 + */ + public function execute($configData) + { + if (!isset($configData['config'][0]['file'])) { + return []; + } + + $files = []; + foreach ($configData['config'][0]['file'] as $fileData) { + /** just one set of providers is allowed by xsd */ + $providers = reset($fileData['providers']); + foreach ($providers as $providerType => $providerDataSet) { + /** just one set of provider data is allowed by xsd */ + $providerData = reset($providerDataSet); + /** just one set of parameters is allowed by xsd */ + $providerData['parameters'] = !empty($providerData['parameters']) + ? reset($providerData['parameters']) + : []; + $providerData['parameters'] = array_map( + 'reset', + $providerData['parameters'] + ); + $providers[$providerType] = $providerData; + } + $files[$fileData['name']] = $fileData; + $files[$fileData['name']]['providers'] = $providers; + } + return $files; + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Reader.php b/app/code/Magento/Analytics/Model/Config/Reader.php new file mode 100644 index 0000000000000..e5e120f95bbd6 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Reader.php @@ -0,0 +1,57 @@ +mapper = $mapper; + $this->readers = $readers; + } + + /** + * Read configuration scope. + * + * @param string|null $scope + * @return array + * @since 2.2.0 + */ + public function read($scope = null) + { + $data = []; + foreach ($this->readers as $reader) { + $data = array_merge_recursive($data, $reader->read($scope)); + } + + return $this->mapper->execute($data); + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Source/Vertical.php b/app/code/Magento/Analytics/Model/Config/Source/Vertical.php new file mode 100644 index 0000000000000..7aac0b070af4b --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Source/Vertical.php @@ -0,0 +1,55 @@ +verticals = $verticals; + } + + /** + * {@inheritdoc} + * @since 2.2.0 + */ + public function toOptionArray() + { + $result = [ + ['value' => '', 'label' => __('--Please Select--')] + ]; + + foreach ($this->verticals as $vertical) { + $result[] = ['value' => $vertical, 'label' => __($vertical)]; + } + + return $result; + } +} diff --git a/app/code/Magento/Analytics/Model/ConfigInterface.php b/app/code/Magento/Analytics/Model/ConfigInterface.php new file mode 100644 index 0000000000000..2f84f9bffe8de --- /dev/null +++ b/app/code/Magento/Analytics/Model/ConfigInterface.php @@ -0,0 +1,24 @@ + 'command_class_name'. + * + * The list may be configured in each module via '/etc/di.xml'. + * + * @var string[] + * @since 2.2.0 + */ + private $commands; + + /** + * @var ObjectManagerInterface + * @since 2.2.0 + */ + private $objectManager; + + /** + * @param array $commands + * @param ObjectManagerInterface $objectManager + * @since 2.2.0 + */ + public function __construct( + array $commands, + ObjectManagerInterface $objectManager + ) { + $this->commands = $commands; + $this->objectManager = $objectManager; + } + + /** + * Executes a command in accordance with the given name. + * + * @param string $commandName + * @return bool + * @throws NotFoundException if the command is not found. + * @since 2.2.0 + */ + public function execute($commandName) + { + if (!array_key_exists($commandName, $this->commands)) { + throw new NotFoundException(__('Command was not found.')); + } + + /** @var \Magento\Analytics\Model\Connector\CommandInterface $command */ + $command = $this->objectManager->create($this->commands[$commandName]); + + return $command->execute(); + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/CommandInterface.php b/app/code/Magento/Analytics/Model/Connector/CommandInterface.php new file mode 100644 index 0000000000000..cf7fe4e24f721 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/CommandInterface.php @@ -0,0 +1,23 @@ +curlFactory = $curlFactory; + $this->responseFactory = $responseFactory; + $this->converter = $converter; + $this->logger = $logger; + } + + /** + * {@inheritdoc} + * @since 2.2.0 + */ + public function request($method, $url, array $body = [], array $headers = [], $version = '1.1') + { + $response = new \Zend_Http_Response(0, []); + + try { + $curl = $this->curlFactory->create(); + $headers = $this->applyContentTypeHeaderFromConverter($headers); + + $curl->write($method, $url, $version, $headers, $this->converter->toBody($body)); + + $result = $curl->read(); + + if ($curl->getErrno()) { + $this->logger->critical( + new \Exception( + sprintf( + 'MBI service CURL connection error #%s: %s', + $curl->getErrno(), + $curl->getError() + ) + ) + ); + + return $response; + } + + $response = $this->responseFactory->create($result); + } catch (\Exception $e) { + $this->logger->critical($e); + } + + return $response; + } + + /** + * @param array $headers + * + * @return array + * @since 2.2.0 + */ + private function applyContentTypeHeaderFromConverter(array $headers) + { + $contentTypeHeaderKey = array_search($this->converter->getContentTypeHeader(), $headers); + if ($contentTypeHeaderKey === false) { + $headers[] = $this->converter->getContentTypeHeader(); + } + + return $headers; + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php b/app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php new file mode 100644 index 0000000000000..aa2a8ca2cbf1a --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php @@ -0,0 +1,31 @@ +converter = $converter; + $this->responseHandlers = $responseHandlers; + } + + /** + * @param \Zend_Http_Response $response + * + * @return bool|string + * @since 2.2.0 + */ + public function getResult(\Zend_Http_Response $response) + { + $result = false; + $responseBody = $this->converter->fromBody($response->getBody()); + if (array_key_exists($response->getStatus(), $this->responseHandlers)) { + $result = $this->responseHandlers[$response->getStatus()]->handleResponse($responseBody); + } + + return $result; + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php b/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php new file mode 100644 index 0000000000000..a88b87a447072 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php @@ -0,0 +1,102 @@ +analyticsToken = $analyticsToken; + $this->httpClient = $httpClient; + $this->config = $config; + $this->responseResolver = $responseResolver; + $this->logger = $logger; + } + + /** + * Notify MBI about that data collection was finished + * + * @return bool + * @since 2.2.0 + */ + public function execute() + { + $result = false; + if ($this->analyticsToken->isTokenExist()) { + $response = $this->httpClient->request( + ZendClient::POST, + $this->config->getValue($this->notifyDataChangedUrlPath), + [ + "access-token" => $this->analyticsToken->getToken(), + "url" => $this->config->getValue(Store::XML_PATH_SECURE_BASE_URL), + ] + ); + $result = $this->responseResolver->getResult($response); + } + return (bool)$result; + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/OTPRequest.php b/app/code/Magento/Analytics/Model/Connector/OTPRequest.php new file mode 100644 index 0000000000000..f0577084cbff3 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/OTPRequest.php @@ -0,0 +1,124 @@ +analyticsToken = $analyticsToken; + $this->httpClient = $httpClient; + $this->config = $config; + $this->responseResolver = $responseResolver; + $this->logger = $logger; + } + + /** + * Performs obtaining of an OTP from the MBI service. + * + * Returns received OTP or FALSE in case of failure. + * + * @return string|false + * @since 2.2.0 + */ + public function call() + { + $result = false; + + if ($this->analyticsToken->isTokenExist()) { + $response = $this->httpClient->request( + ZendClient::POST, + $this->config->getValue($this->otpUrlConfigPath), + [ + "access-token" => $this->analyticsToken->getToken(), + "url" => $this->config->getValue(Store::XML_PATH_SECURE_BASE_URL), + ] + ); + + $result = $this->responseResolver->getResult($response); + if (!$result) { + $this->logger->warning( + sprintf( + 'Obtaining of an OTP from the MBI service has been failed: %s', + !empty($response->getBody()) ? $response->getBody() : 'Response body is empty.' + ) + ); + } + } + + return $result; + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php new file mode 100644 index 0000000000000..d385f466e2919 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php @@ -0,0 +1,26 @@ +analyticsToken = $analyticsToken; + $this->subscriptionHandler = $subscriptionHandler; + $this->subscriptionStatusProvider = $subscriptionStatusProvider; + } + + /** + * @inheritdoc + * @since 2.2.0 + */ + public function handleResponse(array $responseBody) + { + if ($this->subscriptionStatusProvider->getStatus() === SubscriptionStatusProvider::ENABLED) { + $this->analyticsToken->storeToken(null); + $this->subscriptionHandler->processEnabled(); + } + return false; + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php new file mode 100644 index 0000000000000..49ad1936a3975 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php @@ -0,0 +1,56 @@ +analyticsToken = $analyticsToken; + $this->converter = $converter; + } + + /** + * @inheritdoc + * @since 2.2.0 + */ + public function handleResponse(array $body) + { + if (isset($body['access-token']) && !empty($body['access-token'])) { + $this->analyticsToken->storeToken($body['access-token']); + return $body['access-token']; + } + + return false; + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php new file mode 100644 index 0000000000000..13a7eaa9b1fd8 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php @@ -0,0 +1,26 @@ +analyticsToken = $analyticsToken; + $this->integrationManager = $integrationManager; + $this->config = $config; + $this->httpClient = $httpClient; + $this->logger = $logger; + $this->responseResolver = $responseResolver; + } + + /** + * Executes signUp command + * + * During this call Magento generates or retrieves access token for the integration user + * In case successful generation Magento activates user and sends access token to MA + * As the response, Magento receives a token to MA + * Magento stores this token in System Configuration + * + * This method returns true in case of success + * + * @return bool + * @since 2.2.0 + */ + public function execute() + { + $result = false; + $integrationToken = $this->integrationManager->generateToken(); + if ($integrationToken) { + $this->integrationManager->activateIntegration(); + $response = $this->httpClient->request( + ZendClient::POST, + $this->config->getValue($this->signUpUrlPath), + [ + "token" => $integrationToken->getData('token'), + "url" => $this->config->getValue(Store::XML_PATH_SECURE_BASE_URL), + ] + ); + + $result = $this->responseResolver->getResult($response); + if (!$result) { + $this->logger->warning( + sprintf( + 'Subscription for MBI service has been failed. An error occurred during token exchange: %s', + !empty($response->getBody()) ? $response->getBody() : 'Response body is empty.' + ) + ); + } + } + + return (bool)$result; + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php b/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php new file mode 100644 index 0000000000000..ff8ad2ec85a43 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php @@ -0,0 +1,124 @@ +analyticsToken = $analyticsToken; + $this->httpClient = $httpClient; + $this->config = $config; + $this->logger = $logger; + $this->flagManager = $flagManager; + $this->responseResolver = $responseResolver; + } + + /** + * Executes update request to MBI api in case store url was changed + * + * @return bool + * @since 2.2.0 + */ + public function execute() + { + $result = false; + if ($this->analyticsToken->isTokenExist()) { + $response = $this->httpClient->request( + ZendClient::PUT, + $this->config->getValue($this->updateUrlPath), + [ + "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(), + ] + ); + $result = $this->responseResolver->getResult($response); + if (!$result) { + $this->logger->warning( + sprintf( + 'Update of the subscription for MBI service has been failed: %s', + !empty($response->getBody()) ? $response->getBody() : 'Response body is empty.' + ) + ); + } + } + + return (bool)$result; + } +} diff --git a/app/code/Magento/Analytics/Model/Cryptographer.php b/app/code/Magento/Analytics/Model/Cryptographer.php new file mode 100644 index 0000000000000..848d2911e9a5e --- /dev/null +++ b/app/code/Magento/Analytics/Model/Cryptographer.php @@ -0,0 +1,140 @@ +analyticsToken = $analyticsToken; + $this->encodedContextFactory = $encodedContextFactory; + } + + /** + * Encrypt input data. + * + * @param string $source + * @return EncodedContext + * @throws LocalizedException + * @since 2.2.0 + */ + public function encode($source) + { + if (!is_string($source)) { + try { + $source = (string)$source; + } catch (\Exception $e) { + throw new LocalizedException(__('Input data must be string or convertible into string.')); + } + } elseif (!$source) { + throw new LocalizedException(__('Input data must be non-empty string.')); + } + if (!$this->validateCipherMethod($this->cipherMethod)) { + throw new LocalizedException(__('Not valid cipher method.')); + } + $initializationVector = $this->getInitializationVector(); + + $encodedContext = $this->encodedContextFactory->create([ + 'content' => openssl_encrypt( + $source, + $this->cipherMethod, + $this->getKey(), + OPENSSL_RAW_DATA, + $initializationVector + ), + 'initializationVector' => $initializationVector, + ]); + + return $encodedContext; + } + + /** + * Return key for encryption. + * + * @return string + * @throws LocalizedException + * @since 2.2.0 + */ + private function getKey() + { + $token = $this->analyticsToken->getToken(); + if (!$token) { + throw new LocalizedException(__('Encryption key can\'t be empty.')); + } + return hash('sha256', $token); + } + + /** + * Return established cipher method. + * + * @return string + * @since 2.2.0 + */ + private function getCipherMethod() + { + return $this->cipherMethod; + } + + /** + * Return each time generated random initialization vector which depends on the cipher method. + * + * @return string + * @since 2.2.0 + */ + private function getInitializationVector() + { + $ivSize = openssl_cipher_iv_length($this->getCipherMethod()); + return openssl_random_pseudo_bytes($ivSize); + } + + /** + * Check that cipher method is allowed for encryption. + * + * @param string $cipherMethod + * @return bool + * @since 2.2.0 + */ + private function validateCipherMethod($cipherMethod) + { + $methods = openssl_get_cipher_methods(); + return (false !== array_search($cipherMethod, $methods)); + } +} diff --git a/app/code/Magento/Analytics/Model/EncodedContext.php b/app/code/Magento/Analytics/Model/EncodedContext.php new file mode 100644 index 0000000000000..bffbf29315c11 --- /dev/null +++ b/app/code/Magento/Analytics/Model/EncodedContext.php @@ -0,0 +1,58 @@ +content = $content; + $this->initializationVector = $initializationVector; + } + + /** + * @return string + * @since 2.2.0 + */ + public function getContent() + { + return $this->content; + } + + /** + * @return string + * @since 2.2.0 + */ + public function getInitializationVector() + { + return $this->initializationVector; + } +} 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..74cfd28365678 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php @@ -0,0 +1,18 @@ +filesystem = $filesystem; + $this->archive = $archive; + $this->reportWriter = $reportWriter; + $this->cryptographer = $cryptographer; + $this->fileRecorder = $fileRecorder; + } + + /** + * @inheritdoc + * @since 2.2.0 + */ + public function prepareExportData() + { + try { + $tmpDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::SYS_TMP); + + $this->prepareDirectory($tmpDirectory, $this->getTmpFilesDirRelativePath()); + $this->reportWriter->write($tmpDirectory, $this->getTmpFilesDirRelativePath()); + + $tmpFilesDirectoryAbsolutePath = $this->validateSource($tmpDirectory, $this->getTmpFilesDirRelativePath()); + $archiveAbsolutePath = $this->prepareFileDirectory($tmpDirectory, $this->getArchiveRelativePath()); + $this->pack( + $tmpFilesDirectoryAbsolutePath, + $archiveAbsolutePath + ); + + $this->validateSource($tmpDirectory, $this->getArchiveRelativePath()); + $this->fileRecorder->recordNewFile( + $this->cryptographer->encode($tmpDirectory->readFile($this->getArchiveRelativePath())) + ); + } finally { + $tmpDirectory->delete($this->getTmpFilesDirRelativePath()); + $tmpDirectory->delete($this->getArchiveRelativePath()); + } + + return true; + } + + /** + * Return relative path to a directory for temporary files with reports data. + * + * @return string + * @since 2.2.0 + */ + private function getTmpFilesDirRelativePath() + { + return $this->subdirectoryPath . 'tmp/'; + } + + /** + * Return relative path to a directory for an archive. + * + * @return string + * @since 2.2.0 + */ + private function getArchiveRelativePath() + { + return $this->subdirectoryPath . $this->archiveName; + } + + /** + * Clean up a directory. + * + * @param WriteInterface $directory + * @param string $path + * @return string + * @since 2.2.0 + */ + private function prepareDirectory(WriteInterface $directory, $path) + { + $directory->delete($path); + + return $directory->getAbsolutePath($path); + } + + /** + * Remove a file and a create parent directory a file. + * + * @param WriteInterface $directory + * @param string $path + * @return string + * @since 2.2.0 + */ + private function prepareFileDirectory(WriteInterface $directory, $path) + { + $directory->delete($path); + if (dirname($path) !== '.') { + $directory->create(dirname($path)); + } + + return $directory->getAbsolutePath($path); + } + + /** + * Packing data into an archive. + * + * @param string $source + * @param string $destination + * @return bool + * @since 2.2.0 + */ + private function pack($source, $destination) + { + $this->archive->pack( + $source, + $destination, + is_dir($source) ?: false + ); + + return true; + } + + /** + * Validate that data source exist. + * + * Return absolute path in a validated data source. + * + * @param WriteInterface $directory + * @param string $path + * @return string + * @throws LocalizedException If source is not exist. + * @since 2.2.0 + */ + private function validateSource(WriteInterface $directory, $path) + { + if (!$directory->isExist($path)) { + throw new LocalizedException(__('Source "%1" is not exist', $directory->getAbsolutePath($path))); + } + + return $directory->getAbsolutePath($path); + } +} diff --git a/app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php b/app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php new file mode 100644 index 0000000000000..c8af595c2aadf --- /dev/null +++ b/app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php @@ -0,0 +1,21 @@ +exportDataHandler = $exportDataHandler; + $this->analyticsConnector = $connector; + } + + /** + * {@inheritdoc} + * Execute notification command. + * + * @return bool + * @since 2.2.0 + */ + public function prepareExportData() + { + $result = $this->exportDataHandler->prepareExportData(); + $this->analyticsConnector->execute('notifyDataChanged'); + return $result; + } +} diff --git a/app/code/Magento/Analytics/Model/FileInfo.php b/app/code/Magento/Analytics/Model/FileInfo.php new file mode 100644 index 0000000000000..edfac858d6f68 --- /dev/null +++ b/app/code/Magento/Analytics/Model/FileInfo.php @@ -0,0 +1,58 @@ +path = $path; + $this->initializationVector = $initializationVector; + } + + /** + * @return string + * @since 2.2.0 + */ + public function getPath() + { + return $this->path; + } + + /** + * @return string + * @since 2.2.0 + */ + public function getInitializationVector() + { + return $this->initializationVector; + } +} diff --git a/app/code/Magento/Analytics/Model/FileInfoManager.php b/app/code/Magento/Analytics/Model/FileInfoManager.php new file mode 100644 index 0000000000000..204995e133d20 --- /dev/null +++ b/app/code/Magento/Analytics/Model/FileInfoManager.php @@ -0,0 +1,133 @@ +flagManager = $flagManager; + $this->fileInfoFactory = $fileInfoFactory; + } + + /** + * Save FileInfo object. + * + * @param FileInfo $fileInfo + * @return bool + * @throws LocalizedException + * @since 2.2.0 + */ + public function save(FileInfo $fileInfo) + { + $parameters = []; + $parameters['initializationVector'] = $fileInfo->getInitializationVector(); + $parameters['path'] = $fileInfo->getPath(); + + $emptyParameters = array_diff($parameters, array_filter($parameters)); + if ($emptyParameters) { + throw new LocalizedException( + __('These arguments can\'t be empty "%1"', implode(', ', array_keys($emptyParameters))) + ); + } + + foreach ($this->encodedParameters as $encodedParameter) { + $parameters[$encodedParameter] = $this->encodeValue($parameters[$encodedParameter]); + } + + $this->flagManager->saveFlag($this->flagCode, $parameters); + + return true; + } + + /** + * Load FileInfo object. + * + * @return FileInfo + * @since 2.2.0 + */ + public function load() + { + $parameters = $this->flagManager->getFlagData($this->flagCode) ?: []; + + $encodedParameters = array_intersect($this->encodedParameters, array_keys($parameters)); + foreach ($encodedParameters as $encodedParameter) { + $parameters[$encodedParameter] = $this->decodeValue($parameters[$encodedParameter]); + } + + $fileInfo = $this->fileInfoFactory->create($parameters); + + return $fileInfo; + } + + /** + * Encode value. + * + * @param string $value + * @return string + * @since 2.2.0 + */ + private function encodeValue($value) + { + return base64_encode($value); + } + + /** + * Decode value. + * + * @param string $value + * @return string + * @since 2.2.0 + */ + private function decodeValue($value) + { + return base64_decode($value); + } +} diff --git a/app/code/Magento/Analytics/Model/FileRecorder.php b/app/code/Magento/Analytics/Model/FileRecorder.php new file mode 100644 index 0000000000000..94e0c59d9321b --- /dev/null +++ b/app/code/Magento/Analytics/Model/FileRecorder.php @@ -0,0 +1,147 @@ +fileInfoManager = $fileInfoManager; + $this->fileInfoFactory = $fileInfoFactory; + $this->filesystem = $filesystem; + } + + /** + * Save new encrypted file, register it and remove old registered file. + * + * @param EncodedContext $encodedContext + * @return bool + * @since 2.2.0 + */ + public function recordNewFile(EncodedContext $encodedContext) + { + $directory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); + + $fileRelativePath = $this->getFileRelativePath(); + $directory->writeFile($fileRelativePath, $encodedContext->getContent()); + + $fileInfo = $this->fileInfoManager->load(); + $this->registerFile($encodedContext, $fileRelativePath); + $this->removeOldFile($fileInfo, $directory); + + return true; + } + + /** + * Return relative path to encoded file. + * + * @return string + * @since 2.2.0 + */ + private function getFileRelativePath() + { + return $this->fileSubdirectoryPath . hash('sha256', time()) + . '/' . $this->encodedFileName; + } + + /** + * Register encoded file. + * + * @param EncodedContext $encodedContext + * @param string $fileRelativePath + * @return bool + * @since 2.2.0 + */ + private function registerFile(EncodedContext $encodedContext, $fileRelativePath) + { + $newFileInfo = $this->fileInfoFactory->create( + [ + 'path' => $fileRelativePath, + 'initializationVector' => $encodedContext->getInitializationVector(), + ] + ); + $this->fileInfoManager->save($newFileInfo); + + return true; + } + + /** + * Remove previously registered file. + * + * @param FileInfo $fileInfo + * @param WriteInterface $directory + * @return bool + * @since 2.2.0 + */ + private function removeOldFile(FileInfo $fileInfo, WriteInterface $directory) + { + if (!$fileInfo->getPath()) { + return true; + } + + $directory->delete($fileInfo->getPath()); + + $directoryName = dirname($fileInfo->getPath()); + if ($directoryName !== '.') { + $directory->delete($directoryName); + } + + return true; + } +} diff --git a/app/code/Magento/Analytics/Model/IntegrationManager.php b/app/code/Magento/Analytics/Model/IntegrationManager.php new file mode 100644 index 0000000000000..b2694ac8241c1 --- /dev/null +++ b/app/code/Magento/Analytics/Model/IntegrationManager.php @@ -0,0 +1,135 @@ +integrationService = $integrationService; + $this->config = $config; + $this->oauthService = $oauthService; + } + + /** + * Activate predefined integration user + * + * @return bool + * @throws NoSuchEntityException + * @since 2.2.0 + */ + public function activateIntegration() + { + $integration = $this->integrationService->findByName( + $this->config->getConfigDataValue('analytics/integration_name') + ); + if (!$integration->getId()) { + throw new NoSuchEntityException(__('Cannot find predefined integration user!')); + } + $integrationData = $this->getIntegrationData(Integration::STATUS_ACTIVE); + $integrationData['integration_id'] = $integration->getId(); + $this->integrationService->update($integrationData); + return true; + } + + /** + * This method execute Generate Token command and enable integration + * + * @return bool|\Magento\Integration\Model\Oauth\Token + * @since 2.2.0 + */ + public function generateToken() + { + $consumerId = $this->generateIntegration()->getConsumerId(); + $accessToken = $this->oauthService->getAccessToken($consumerId); + if (!$accessToken && $this->oauthService->createAccessToken($consumerId, true)) { + $accessToken = $this->oauthService->getAccessToken($consumerId); + } + return $accessToken; + } + + /** + * Returns consumer Id for MA integration user + * + * @return \Magento\Integration\Model\Integration + * @since 2.2.0 + */ + private function generateIntegration() + { + $integration = $this->integrationService->findByName( + $this->config->getConfigDataValue('analytics/integration_name') + ); + if (!$integration->getId()) { + $integration = $this->integrationService->create($this->getIntegrationData()); + } + return $integration; + } + + /** + * Returns default attributes for MA integration user + * + * @param int $status + * @return array + * @since 2.2.0 + */ + private function getIntegrationData($status = Integration::STATUS_INACTIVE) + { + $integrationData = [ + 'name' => $this->config->getConfigDataValue('analytics/integration_name'), + 'status' => $status, + 'all_resources' => false, + 'resource' => [ + 'Magento_Analytics::analytics', + 'Magento_Analytics::analytics_api' + ], + ]; + return $integrationData; + } +} diff --git a/app/code/Magento/Analytics/Model/Link.php b/app/code/Magento/Analytics/Model/Link.php new file mode 100644 index 0000000000000..34479e9ae4f61 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Link.php @@ -0,0 +1,60 @@ +url = $url; + $this->initializationVector = $initializationVector; + } + + /** + * @return string + * @since 2.2.0 + */ + public function getUrl() + { + return $this->url; + } + + /** + * @return string + * @since 2.2.0 + */ + public function getInitializationVector() + { + return $this->initializationVector; + } +} diff --git a/app/code/Magento/Analytics/Model/LinkProvider.php b/app/code/Magento/Analytics/Model/LinkProvider.php new file mode 100644 index 0000000000000..6d09e20fef1a4 --- /dev/null +++ b/app/code/Magento/Analytics/Model/LinkProvider.php @@ -0,0 +1,95 @@ +linkFactory = $linkFactory; + $this->fileInfoManager = $fileInfoManager; + $this->storeManager = $storeManager; + } + + /** + * Returns base url to file according to store configuration + * + * @param FileInfo $fileInfo + * @return string + * @since 2.2.0 + */ + private function getBaseUrl(FileInfo $fileInfo) + { + return $this->storeManager->getStore()->getBaseUrl(UrlInterface::URL_TYPE_MEDIA) . $fileInfo->getPath(); + } + + /** + * Verify is requested file ready + * + * @param FileInfo $fileInfo + * @return bool + * @since 2.2.0 + */ + private function isFileReady(FileInfo $fileInfo) + { + return $fileInfo->getPath() && $fileInfo->getInitializationVector(); + } + + /** + * @inheritdoc + * @since 2.2.0 + */ + public function get() + { + $fileInfo = $this->fileInfoManager->load(); + if (!$this->isFileReady($fileInfo)) { + throw new NoSuchEntityException(__('File is not ready yet.')); + } + return $this->linkFactory->create( + [ + 'url' => $this->getBaseUrl($fileInfo), + 'initializationVector' => base64_encode($fileInfo->getInitializationVector()) + ] + ); + } +} diff --git a/app/code/Magento/Analytics/Model/NotificationTime.php b/app/code/Magento/Analytics/Model/NotificationTime.php new file mode 100644 index 0000000000000..c36f830a70762 --- /dev/null +++ b/app/code/Magento/Analytics/Model/NotificationTime.php @@ -0,0 +1,72 @@ +flagManager = $flagManager; + } + + /** + * Stores last notification time + * + * @param string $value + * @return bool + * @since 2.2.0 + */ + public function storeLastTimeNotification($value) + { + return $this->flagManager->saveFlag(self::NOTIFICATION_TIME, $value); + } + + /** + * Returns last time when merchant was notified about Analytic services + * + * @return int + * @since 2.2.0 + */ + public function getLastTimeNotification() + { + return $this->flagManager->getFlagData(self::NOTIFICATION_TIME); + } + + /** + * Remove last notification time flag. + * + * @return bool + * @since 2.2.0 + */ + public function unsetLastTimeNotificationValue() + { + return $this->flagManager->deleteFlag(self::NOTIFICATION_TIME); + } +} diff --git a/app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php b/app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php new file mode 100644 index 0000000000000..e2bdf354b040c --- /dev/null +++ b/app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php @@ -0,0 +1,66 @@ +subscriptionUpdateHandler = $subscriptionUpdateHandler; + } + + /** + * Add additional handling after config value was saved. + * + * @param Value $subject + * @param Value $result + * @return Value + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function afterAfterSave( + Value $subject, + Value $result + ) { + if ($this->isPluginApplicable($result)) { + $this->subscriptionUpdateHandler->processUrlUpdate($result->getOldValue()); + } + + return $result; + } + + /** + * @param Value $result + * @return bool + * @since 2.2.0 + */ + private function isPluginApplicable(Value $result) + { + 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/ProviderFactory.php b/app/code/Magento/Analytics/Model/ProviderFactory.php new file mode 100644 index 0000000000000..35af7d5ddaa1c --- /dev/null +++ b/app/code/Magento/Analytics/Model/ProviderFactory.php @@ -0,0 +1,43 @@ +objectManager = $objectManager; + } + + /** + * @param string $providerName + * @return object + * @since 2.2.0 + */ + public function create($providerName) + { + return $this->objectManager->get($providerName); + } +} diff --git a/app/code/Magento/Analytics/Model/ReportUrlProvider.php b/app/code/Magento/Analytics/Model/ReportUrlProvider.php new file mode 100644 index 0000000000000..dfa27358e252b --- /dev/null +++ b/app/code/Magento/Analytics/Model/ReportUrlProvider.php @@ -0,0 +1,102 @@ +analyticsToken = $analyticsToken; + $this->otpRequest = $otpRequest; + $this->config = $config; + $this->flagManager = $flagManager; + } + + /** + * Provide URL on resource with reports. + * + * @return string + * @throws SubscriptionUpdateException + * @since 2.2.0 + */ + 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(); + if ($otp) { + $query = http_build_query(['otp' => $otp], '', '&'); + $url .= '?' . $query; + } + } + + return $url; + } +} diff --git a/app/code/Magento/Analytics/Model/ReportWriter.php b/app/code/Magento/Analytics/Model/ReportWriter.php new file mode 100644 index 0000000000000..ae3522c6f4351 --- /dev/null +++ b/app/code/Magento/Analytics/Model/ReportWriter.php @@ -0,0 +1,108 @@ +config = $config; + $this->reportValidator = $reportValidator; + $this->providerFactory = $providerFactory; + } + + /** + * {@inheritdoc} + * @since 2.2.0 + */ + public function write(WriteInterface $directory, $path) + { + $errorsList = []; + foreach ($this->config->get() as $file) { + $provider = reset($file['providers']); + if (isset($provider['parameters']['name'])) { + $error = $this->reportValidator->validate($provider['parameters']['name']); + if ($error) { + $errorsList[] = $error; + continue; + } + } + /** @var $providerObject */ + $providerObject = $this->providerFactory->create($provider['class']); + $fileName = $provider['parameters'] ? $provider['parameters']['name'] : $provider['name']; + $fileFullPath = $path . $fileName . '.csv'; + $fileData = $providerObject->getReport(...array_values($provider['parameters'])); + $stream = $directory->openFile($fileFullPath, 'w+'); + $stream->lock(); + $headers = []; + foreach ($fileData as $row) { + if (!$headers) { + $headers = array_keys($row); + $stream->writeCsv($headers); + } + $stream->writeCsv($row); + } + $stream->unlock(); + $stream->close(); + } + if ($errorsList) { + $errorStream = $directory->openFile($path . $this->errorsFileName, 'w+'); + foreach ($errorsList as $error) { + $errorStream->lock(); + $errorStream->writeCsv($error); + $errorStream->unlock(); + } + $errorStream->close(); + } + + return true; + } +} diff --git a/app/code/Magento/Analytics/Model/ReportWriterInterface.php b/app/code/Magento/Analytics/Model/ReportWriterInterface.php new file mode 100644 index 0000000000000..bb7f8dfbe26a6 --- /dev/null +++ b/app/code/Magento/Analytics/Model/ReportWriterInterface.php @@ -0,0 +1,30 @@ +moduleManager = $moduleManager; + } + + /** + * Returns module with module status + * + * @return array + * @since 2.2.0 + */ + public function current() + { + $current = parent::current(); + if (is_array($current) && isset($current['module_name'])) { + $current['status'] = + $this->moduleManager->isEnabled($current['module_name']) == 1 ? 'Enabled' : "Disabled"; + } + return $current; + } +} diff --git a/app/code/Magento/Analytics/Model/StoreConfigurationProvider.php b/app/code/Magento/Analytics/Model/StoreConfigurationProvider.php new file mode 100644 index 0000000000000..e070e2c669ccf --- /dev/null +++ b/app/code/Magento/Analytics/Model/StoreConfigurationProvider.php @@ -0,0 +1,109 @@ +scopeConfig = $scopeConfig; + $this->configPaths = $configPaths; + $this->storeManager = $storeManager; + } + + /** + * Generates report using config paths from di.xml + * For each website and store + * @return \IteratorIterator + * @since 2.2.0 + */ + public function getReport() + { + $configReport = $this->generateReportForScope(ScopeConfigInterface::SCOPE_TYPE_DEFAULT, 0); + + /** @var WebsiteInterface $website */ + foreach ($this->storeManager->getWebsites() as $website) { + $configReport = array_merge( + $this->generateReportForScope(ScopeInterface::SCOPE_WEBSITES, $website->getId()), + $configReport + ); + } + + /** @var StoreInterface $store */ + foreach ($this->storeManager->getStores() as $store) { + $configReport = array_merge( + $this->generateReportForScope(ScopeInterface::SCOPE_STORES, $store->getId()), + $configReport + ); + } + return new \IteratorIterator(new \ArrayIterator($configReport)); + } + + /** + * Creates report from config for scope type and scope id. + * + * @param string $scope + * @param int $scopeId + * @return array + * @since 2.2.0 + */ + private function generateReportForScope($scope, $scopeId) + { + $report = []; + foreach ($this->configPaths as $configPath) { + $report[] = [ + "config_path" => $configPath, + "scope" => $scope, + "scope_id" => $scopeId, + "value" => $this->scopeConfig->getValue( + $configPath, + $scope, + $scopeId + ) + ]; + } + return $report; + } +} diff --git a/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php b/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php new file mode 100644 index 0000000000000..478e0ae4ccd63 --- /dev/null +++ b/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php @@ -0,0 +1,128 @@ +scopeConfig = $scopeConfig; + $this->analyticsToken = $analyticsToken; + $this->flagManager = $flagManager; + } + + /** + * Retrieve subscription status to Magento BI Advanced Reporting. + * + * Statuses: + * Enabled - if subscription is enabled and MA token was received; + * Pending - if subscription is enabled and MA token was not received; + * Disabled - if subscription is not enabled. + * Failed - if subscription is enabled and token was not received after attempts ended. + * + * @return string + * @since 2.2.0 + */ + public function getStatus() + { + $isSubscriptionEnabledInConfig = $this->scopeConfig->getValue('analytics/subscription/enabled'); + if ($isSubscriptionEnabledInConfig) { + return $this->getStatusForEnabledSubscription(); + } + + return $this->getStatusForDisabledSubscription(); + } + + /** + * Retrieve status for subscription that enabled in config. + * + * @return string + * @since 2.2.0 + */ + 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) { + $status = static::FAILED; + } + } + + return $status; + } + + /** + * Retrieve status for subscription that disabled in config. + * + * @return string + * @since 2.2.0 + */ + public function getStatusForDisabledSubscription() + { + return static::DISABLED; + } +} diff --git a/app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php b/app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php new file mode 100644 index 0000000000000..688caedf8e864 --- /dev/null +++ b/app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php @@ -0,0 +1,88 @@ +subscriptionStatusProvider = $subscriptionStatusProvider; + $this->urlBuilder = $urlBuilder; + } + + /** + * @inheritdoc + * + * @codeCoverageIgnore + * @since 2.2.0 + */ + public function getIdentity() + { + return hash('sha256', 'ANALYTICS_NOTIFICATION'); + } + + /** + * {@inheritdoc} + * @since 2.2.0 + */ + public function isDisplayed() + { + return $this->subscriptionStatusProvider->getStatus() === SubscriptionStatusProvider::FAILED; + } + + /** + * {@inheritdoc} + * @since 2.2.0 + */ + public function getText() + { + $messageDetails = ''; + + $messageDetails .= __('Failed to synchronize data to the Magento Business Intelligence service. '); + $messageDetails .= __( + 'Retry Synchronization', + $this->urlBuilder->getUrl('analytics/subscription/retry') + ); + + return $messageDetails; + } + + /** + * @inheritdoc + * + * @codeCoverageIgnore + * @since 2.2.0 + */ + public function getSeverity() + { + return self::SEVERITY_MAJOR; + } +} diff --git a/app/code/Magento/Analytics/README.md b/app/code/Magento/Analytics/README.md new file mode 100644 index 0000000000000..ee6d017a1f3ac --- /dev/null +++ b/app/code/Magento/Analytics/README.md @@ -0,0 +1,25 @@ +# Magento_Analytics module + +The Magento_Analytics module integrates your Magento instance with the [Magento Business Intelligence (MBI)](https://magento.com/products/business-intelligence) to use [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html) functionality. + +The module implements the following functionality: + +* enabling subscription to the MBI and automatic re-subscription +* changing the base URL with the same MBI account remained +* declaring the configuration schemas for report data collection +* collecting the Magento instance data as reports for the MBI +* introducing API that provides the collected data +* extending Magento configuration with the module parameters: + * subscription status (enabled/disabled) + * industry (a business area in which the instance website works) + * time of data collection (time of the day when the module collects data) + +## Structure + +Beyond the [usual module file structure](http://devdocs.magento.com/guides/v2.2/architecture/archi_perspectives/components/modules/mod_intro.html) the module contains a directory `ReportXml`. +[Report XML](http://devdocs.magento.com/guides/v2.2/advanced-reporting/report-xml.html) is a markup language used to build reports for Advanced Reporting. +The language declares SQL queries using XML declaration. + +## Extensibility + +We do not recommend to extend the Magento_Analytics module. It introduces an API that is purposed to transfer the collected data. Note that the API cannot be used for other needs. diff --git a/app/code/Magento/Analytics/ReportXml/Config.php b/app/code/Magento/Analytics/ReportXml/Config.php new file mode 100644 index 0000000000000..4176486fd0993 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/Config.php @@ -0,0 +1,47 @@ +data = $data; + } + + /** + * Returns config value by name + * + * @param string $queryName + * @return array + * @since 2.2.0 + */ + public function get($queryName) + { + return $this->data->get($queryName); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php b/app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php new file mode 100644 index 0000000000000..a479b70c91945 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php @@ -0,0 +1,64 @@ +hasAttributes()) { + $attrs = $source->attributes; + foreach ($attrs as $attr) { + $result[$attr->name] = $attr->value; + } + } + if ($source->hasChildNodes()) { + $children = $source->childNodes; + if ($children->length == 1) { + $child = $children->item(0); + if ($child->nodeType == XML_TEXT_NODE) { + $result['_value'] = $child->nodeValue; + return count($result) == 1 ? $result['_value'] : $result; + } + } + foreach ($children as $child) { + if ($child instanceof \DOMCharacterData) { + continue; + } + $result[$child->nodeName][] = $this->convertNode($child); + } + } + return $result; + } + + /** + * Converts XML document into corresponding array. + * + * @param \DOMDocument $source + * @return array + * @since 2.2.0 + */ + public function convert($source) + { + return $this->convertNode($source); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/Config/Mapper.php b/app/code/Magento/Analytics/ReportXml/Config/Mapper.php new file mode 100644 index 0000000000000..8da73e257b825 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/Config/Mapper.php @@ -0,0 +1,39 @@ +readers = $readers; + $this->mapper = $mapper; + } + + /** + * Reads configuration according to the given scope. + * + * @param string|null $scope + * @return array + * @since 2.2.0 + */ + public function read($scope = null) + { + $data = []; + foreach ($this->readers as $reader) { + $data = array_merge_recursive($data, $reader->read($scope)); + } + return $this->mapper->execute($data); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/ConfigInterface.php b/app/code/Magento/Analytics/ReportXml/ConfigInterface.php new file mode 100644 index 0000000000000..b9271700f6758 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/ConfigInterface.php @@ -0,0 +1,25 @@ +resourceConnection = $resourceConnection; + $this->objectManager = $objectManager; + } + + /** + * Creates one-time connection for export + * + * @param string $connectionName + * @return AdapterInterface + * @since 2.2.0 + */ + public function getConnection($connectionName) + { + $connection = $this->resourceConnection->getConnection($connectionName); + $connectionClassName = get_class($connection); + $configData = $connection->getConfig(); + $configData['use_buffered_query'] = false; + unset($configData['persistent']); + return $this->objectManager->create( + $connectionClassName, + [ + 'config' => $configData + ] + ); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php b/app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php new file mode 100644 index 0000000000000..e8c35ad46e2e5 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php @@ -0,0 +1,29 @@ +conditionResolver = $conditionResolver; + $this->nameResolver = $nameResolver; + } + + /** + * Assembles WHERE conditions + * + * @param SelectBuilder $selectBuilder + * @param array $queryConfig + * @return SelectBuilder + * @since 2.2.0 + */ + public function assemble(SelectBuilder $selectBuilder, $queryConfig) + { + if (!isset($queryConfig['source']['filter'])) { + return $selectBuilder; + } + $filters = $this->conditionResolver->getFilter( + $selectBuilder, + $queryConfig['source']['filter'], + $this->nameResolver->getAlias($queryConfig['source']) + ); + $selectBuilder->setFilters(array_merge_recursive($selectBuilder->getFilters(), [$filters])); + return $selectBuilder; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php b/app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php new file mode 100644 index 0000000000000..8b6f739e3ecdc --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php @@ -0,0 +1,75 @@ +nameResolver = $nameResolver; + $this->columnsResolver = $columnsResolver; + $this->resourceConnection = $resourceConnection; + } + + /** + * Assembles FROM condition + * + * @param SelectBuilder $selectBuilder + * @param array $queryConfig + * @return SelectBuilder + * @since 2.2.0 + */ + public function assemble(SelectBuilder $selectBuilder, $queryConfig) + { + $selectBuilder->setFrom( + [ + $this->nameResolver->getAlias($queryConfig['source']) => + $this->resourceConnection + ->getTableName($this->nameResolver->getName($queryConfig['source'])), + ] + ); + $columns = $this->columnsResolver->getColumns($selectBuilder, $queryConfig['source']); + $selectBuilder->setColumns(array_merge($selectBuilder->getColumns(), $columns)); + return $selectBuilder; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php b/app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php new file mode 100644 index 0000000000000..ec83019c39c31 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php @@ -0,0 +1,120 @@ +conditionResolver = $conditionResolver; + $this->nameResolver = $nameResolver; + $this->columnsResolver = $columnsResolver; + $this->resourceConnection = $resourceConnection; + } + + /** + * Assembles JOIN conditions + * + * @param SelectBuilder $selectBuilder + * @param array $queryConfig + * @return SelectBuilder + * @since 2.2.0 + */ + public function assemble(SelectBuilder $selectBuilder, $queryConfig) + { + if (!isset($queryConfig['source']['link-source'])) { + return $selectBuilder; + } + $joins = []; + $filters = $selectBuilder->getFilters(); + + $sourceAlias = $this->nameResolver->getAlias($queryConfig['source']); + + foreach ($queryConfig['source']['link-source'] as $join) { + $joinAlias = $this->nameResolver->getAlias($join); + + $joins[$joinAlias] = [ + 'link-type' => isset($join['link-type']) ? $join['link-type'] : 'left', + 'table' => [ + $joinAlias => $this->resourceConnection + ->getTableName($this->nameResolver->getName($join)), + ], + 'condition' => $this->conditionResolver->getFilter( + $selectBuilder, + $join['using'], + $joinAlias, + $sourceAlias + ) + ]; + if (isset($join['filter'])) { + $filters = array_merge( + $filters, + [ + $this->conditionResolver->getFilter( + $selectBuilder, + $join['filter'], + $joinAlias, + $sourceAlias + ) + ] + ); + } + $columns = $this->columnsResolver->getColumns($selectBuilder, isset($join['attribute']) ? $join : []); + $selectBuilder->setColumns(array_merge($selectBuilder->getColumns(), $columns)); + } + $selectBuilder->setFilters($filters); + $selectBuilder->setJoins(array_merge($selectBuilder->getJoins(), $joins)); + return $selectBuilder; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php b/app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php new file mode 100644 index 0000000000000..5b9279175b5ff --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php @@ -0,0 +1,107 @@ +nameResolver = $nameResolver; + $this->resourceConnection = $resourceConnection; + } + + /** + * Returns connection + * + * @return \Magento\Framework\DB\Adapter\AdapterInterface + * @since 2.2.0 + */ + private function getConnection() + { + if (!$this->connection) { + $this->connection = $this->resourceConnection->getConnection(); + } + return $this->connection; + } + + /** + * Set columns list to SelectBuilder + * + * @param SelectBuilder $selectBuilder + * @param array $entityConfig + * @return array + * @since 2.2.0 + */ + public function getColumns(SelectBuilder $selectBuilder, $entityConfig) + { + if (!isset($entityConfig['attribute'])) { + return []; + } + $group = []; + $columns = $selectBuilder->getColumns(); + foreach ($entityConfig['attribute'] as $attributeData) { + $columnAlias = $this->nameResolver->getAlias($attributeData); + $tableAlias = $this->nameResolver->getAlias($entityConfig); + $columnName = $this->nameResolver->getName($attributeData); + if (isset($attributeData['function'])) { + $prefix = ''; + if (isset($attributeData['distinct']) && $attributeData['distinct'] == true) { + $prefix = ' DISTINCT '; + } + $expression = new ColumnValueExpression( + strtoupper($attributeData['function']) . '(' . $prefix + . $this->getConnection()->quoteIdentifier($tableAlias . '.' . $columnName) + . ')' + ); + } else { + $expression = $tableAlias . '.' . $columnName; + } + $columns[$columnAlias] = $expression; + if (isset($attributeData['group'])) { + $group[$columnAlias] = $expression; + } + } + $selectBuilder->setGroup(array_merge($selectBuilder->getGroup(), $group)); + return $columns; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php b/app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php new file mode 100644 index 0000000000000..96a7b0b95cafd --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php @@ -0,0 +1,175 @@ + '%1$s = %2$s', + 'neq' => '%1$s != %2$s', + 'like' => '%1$s LIKE %2$s', + 'nlike' => '%1$s NOT LIKE %2$s', + 'in' => '%1$s IN(%2$s)', + 'nin' => '%1$s NOT IN(%2$s)', + 'notnull' => '%1$s IS NOT NULL', + 'null' => '%1$s IS NULL', + 'gt' => '%1$s > %2$s', + 'lt' => '%1$s < %2$s', + 'gteq' => '%1$s >= %2$s', + 'lteq' => '%1$s <= %2$s', + 'finset' => 'FIND_IN_SET(%2$s, %1$s)' + ]; + + /** + * @var \Magento\Framework\DB\Adapter\AdapterInterface + * @since 2.2.0 + */ + private $connection; + + /** + * @var ResourceConnection + * @since 2.2.0 + */ + private $resourceConnection; + + /** + * ConditionResolver constructor. + * @param ResourceConnection $resourceConnection + * @since 2.2.0 + */ + public function __construct( + ResourceConnection $resourceConnection + ) { + $this->resourceConnection = $resourceConnection; + } + + /** + * Returns connection + * + * @return \Magento\Framework\DB\Adapter\AdapterInterface + * @since 2.2.0 + */ + private function getConnection() + { + if (!$this->connection) { + $this->connection = $this->resourceConnection->getConnection(); + } + return $this->connection; + } + + /** + * Returns value for condition + * + * @param string $condition + * @param string $referencedEntity + * @return mixed|null|string|\Zend_Db_Expr + * @since 2.2.0 + */ + private function getValue($condition, $referencedEntity) + { + $value = null; + $argument = isset($condition['_value']) ? $condition['_value'] : null; + if (!isset($condition['type'])) { + $condition['type'] = 'value'; + } + + switch ($condition['type']) { + case "value": + $value = $this->getConnection()->quote($argument); + break; + case "variable": + $value = new Expression($argument); + break; + case "identifier": + $value = $this->getConnection()->quoteIdentifier( + $referencedEntity ? $referencedEntity . '.' . $argument : $argument + ); + break; + } + return $value; + } + + /** + * Returns condition for WHERE + * + * @param SelectBuilder $selectBuilder + * @param string $tableName + * @param array $condition + * @param null|string $referencedEntity + * @return string + * @since 2.2.0 + */ + private function getCondition(SelectBuilder $selectBuilder, $tableName, $condition, $referencedEntity = null) + { + $columns = $selectBuilder->getColumns(); + if (isset($columns[$condition['attribute']]) + && $columns[$condition['attribute']] instanceof Expression + ) { + $expression = $columns[$condition['attribute']]; + } else { + $expression = $this->getConnection()->quoteIdentifier($tableName . '.' . $condition['attribute']); + } + return sprintf( + $this->conditionMap[$condition['operator']], + $expression, + $this->getValue($condition, $referencedEntity) + ); + } + + /** + * Build WHERE condition + * + * @param SelectBuilder $selectBuilder + * @param array $filterConfig + * @param string $aliasName + * @param null|string $referencedAlias + * @return array + * @since 2.2.0 + */ + public function getFilter(SelectBuilder $selectBuilder, $filterConfig, $aliasName, $referencedAlias = null) + { + $filtersParts = []; + foreach ($filterConfig as $filter) { + $glue = $filter['glue']; + $parts = []; + foreach ($filter['condition'] as $condition) { + if (isset($condition['type']) && $condition['type'] == 'variable') { + $selectBuilder->setParams(array_merge($selectBuilder->getParams(), [$condition['_value']])); + } + $parts[] = $this->getCondition( + $selectBuilder, + $aliasName, + $condition, + $referencedAlias + ); + } + if (isset($filter['filter'])) { + $parts[] = '(' . $this->getFilter( + $selectBuilder, + $filter['filter'], + $aliasName, + $referencedAlias + ) . ')'; + } + $filtersParts[] = '(' . implode(' ' . strtoupper($glue) . ' ', $parts) . ')'; + } + return implode(' OR ', $filtersParts); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/NameResolver.php b/app/code/Magento/Analytics/ReportXml/DB/NameResolver.php new file mode 100644 index 0000000000000..fdea82ba25426 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/NameResolver.php @@ -0,0 +1,43 @@ +getName($elementConfig); + if (isset($elementConfig['alias'])) { + $alias = $elementConfig['alias']; + } + return $alias; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php b/app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php new file mode 100644 index 0000000000000..1092d5fd1e4fc --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php @@ -0,0 +1,69 @@ +connectionFactory = $connectionFactory; + $this->queryFactory = $queryFactory; + } + + /** + * Tries to do query for provided report with limit 0 and return error information if it failed + * + * @param string $name + * @param SearchCriteriaInterface $criteria + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function validate($name, SearchCriteriaInterface $criteria = null) + { + $query = $this->queryFactory->create($name); + $connection = $this->connectionFactory->getConnection($query->getConnectionName()); + $query->getSelect()->limit(0); + try { + $connection->query($query->getSelect()); + } catch (\Zend_Db_Statement_Exception $e) { + return [$name, $e->getMessage()]; + } + + return []; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php new file mode 100644 index 0000000000000..bb37af94c9419 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php @@ -0,0 +1,318 @@ +resourceConnection = $resourceConnection; + } + + /** + * Get join condition + * + * @return array + * @since 2.2.0 + */ + public function getJoins() + { + return $this->joins; + } + + /** + * Set joins conditions + * + * @param array $joins + * @return void + * @since 2.2.0 + */ + public function setJoins($joins) + { + $this->joins = $joins; + } + + /** + * Get connection name + * + * @return string + * @since 2.2.0 + */ + public function getConnectionName() + { + return $this->connectionName; + } + + /** + * Set connection name + * + * @param string $connectionName + * @return void + * @since 2.2.0 + */ + public function setConnectionName($connectionName) + { + $this->connectionName = $connectionName; + } + + /** + * Get columns + * + * @return array + * @since 2.2.0 + */ + public function getColumns() + { + return $this->columns; + } + + /** + * Set columns + * + * @param array $columns + * @return void + * @since 2.2.0 + */ + public function setColumns($columns) + { + $this->columns = $columns; + } + + /** + * Get filters + * + * @return array + * @since 2.2.0 + */ + public function getFilters() + { + return $this->filters; + } + + /** + * Set filters + * + * @param array $filters + * @return void + * @since 2.2.0 + */ + public function setFilters($filters) + { + $this->filters = $filters; + } + + /** + * Get from condition + * + * @return array + * @since 2.2.0 + */ + public function getFrom() + { + return $this->from; + } + + /** + * Set from condition + * + * @param array $from + * @return void + * @since 2.2.0 + */ + public function setFrom($from) + { + $this->from = $from; + } + + /** + * Process JOIN conditions + * + * @param Select $select + * @param array $joinConfig + * @return Select + * @since 2.2.0 + */ + private function processJoin(Select $select, $joinConfig) + { + switch ($joinConfig['link-type']) { + case 'left': + $select->joinLeft($joinConfig['table'], $joinConfig['condition'], []); + break; + case 'inner': + $select->joinInner($joinConfig['table'], $joinConfig['condition'], []); + break; + case 'right': + $select->joinRight($joinConfig['table'], $joinConfig['condition'], []); + break; + } + return $select; + } + + /** + * Creates Select object + * + * @return Select + * @since 2.2.0 + */ + public function create() + { + $connection = $this->resourceConnection->getConnection($this->getConnectionName()); + $select = $connection->select(); + $select->from($this->getFrom(), []); + $select->columns($this->getColumns()); + foreach ($this->getFilters() as $filter) { + $select->where($filter); + } + foreach ($this->getJoins() as $joinConfig) { + $select = $this->processJoin($select, $joinConfig); + } + if (!empty($this->getGroup())) { + $select->group(implode(', ', $this->getGroup())); + } + return $select; + } + + /** + * Returns group + * + * @return array + * @since 2.2.0 + */ + public function getGroup() + { + return $this->group; + } + + /** + * Set group + * + * @param array $group + * @return void + * @since 2.2.0 + */ + public function setGroup($group) + { + $this->group = $group; + } + + /** + * Get parameters + * + * @return array + * @since 2.2.0 + */ + public function getParams() + { + return $this->params; + } + + /** + * Set parameters + * + * @param array $params + * @return void + * @since 2.2.0 + */ + public function setParams($params) + { + $this->params = $params; + } + + /** + * Get having condition + * + * @return array + * @since 2.2.0 + */ + public function getHaving() + { + return $this->having; + } + + /** + * Set having condition + * + * @param array $having + * @return void + * @since 2.2.0 + */ + public function setHaving($having) + { + $this->having = $having; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php new file mode 100644 index 0000000000000..1866d9282c1e9 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php @@ -0,0 +1,47 @@ +objectManager = $objectManager; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return SelectBuilder + * @since 2.2.0 + */ + public function create(array $data = []) + { + return $this->objectManager->create(SelectBuilder::class, $data); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/IteratorFactory.php b/app/code/Magento/Analytics/ReportXml/IteratorFactory.php new file mode 100644 index 0000000000000..195fad845623f --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/IteratorFactory.php @@ -0,0 +1,66 @@ +objectManager = $objectManager; + $this->defaultIteratorName = $defaultIteratorName; + } + + /** + * Creates instance of the result iterator with the query result as an input + * Result iterator can be changed through report configuration + * + * < ... + * + * Uses IteratorIterator by default + * + * @param \Traversable $result + * @param string|null $iteratorName + * @return \IteratorIterator + * @since 2.2.0 + */ + public function create(\Traversable $result, $iteratorName = null) + { + return $this->objectManager->create( + $iteratorName ?: $this->defaultIteratorName, + [ + 'iterator' => $result + ] + ); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/Query.php b/app/code/Magento/Analytics/ReportXml/Query.php new file mode 100644 index 0000000000000..7e464a5ad46d1 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/Query.php @@ -0,0 +1,105 @@ +select = $select; + $this->connectionName = $connectionName; + $this->selectHydrator = $selectHydrator; + $this->config = $config; + } + + /** + * @return Select + * @since 2.2.0 + */ + public function getSelect() + { + return $this->select; + } + + /** + * @return string + * @since 2.2.0 + */ + public function getConnectionName() + { + return $this->connectionName; + } + + /** + * @return array + * @since 2.2.0 + */ + public function getConfig() + { + return $this->config; + } + + /** + * Specify data which should be serialized to JSON + * @link http://php.net/manual/en/jsonserializable.jsonserialize.php + * @return mixed data which can be serialized by json_encode, + * which is a value of any type other than a resource. + * @since 5.4.0 + */ + public function jsonSerialize() + { + return [ + 'connectionName' => $this->getConnectionName(), + 'select_parts' => $this->selectHydrator->extract($this->getSelect()), + 'config' => $this->getConfig() + ]; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/QueryFactory.php b/app/code/Magento/Analytics/ReportXml/QueryFactory.php new file mode 100644 index 0000000000000..37e6609553023 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/QueryFactory.php @@ -0,0 +1,153 @@ +config = $config; + $this->selectBuilderFactory = $selectBuilderFactory; + $this->assemblers = $assemblers; + $this->queryCache = $queryCache; + $this->objectManager = $objectManager; + $this->selectHydrator = $selectHydrator; + } + + /** + * Returns query connection name according to configuration + * + * @param string $queryConfig + * @return string + * @since 2.2.0 + */ + private function getQueryConnectionName($queryConfig) + { + $connectionName = 'default'; + if (isset($queryConfig['connection'])) { + $connectionName = $queryConfig['connection']; + } + return $connectionName; + } + + /** + * Create query according to configuration settings + * + * @param string $queryName + * @return Query + * @since 2.2.0 + */ + private function constructQuery($queryName) + { + $queryConfig = $this->config->get($queryName); + $selectBuilder = $this->selectBuilderFactory->create(); + $selectBuilder->setConnectionName($this->getQueryConnectionName($queryConfig)); + foreach ($this->assemblers as $assembler) { + $selectBuilder = $assembler->assemble($selectBuilder, $queryConfig); + } + $select = $selectBuilder->create(); + return $this->objectManager->create( + Query::class, + [ + 'select' => $select, + 'selectHydrator' => $this->selectHydrator, + 'connectionName' => $selectBuilder->getConnectionName(), + 'config' => $queryConfig + ] + ); + } + + /** + * Creates query by name + * + * @param string $queryName + * @return Query + * @since 2.2.0 + */ + public function create($queryName) + { + $cached = $this->queryCache->load($queryName); + if ($cached) { + $queryData = json_decode($cached, true); + return $this->objectManager->create( + Query::class, + [ + 'select' => $this->selectHydrator->recreate($queryData['select_parts']), + 'selectHydrator' => $this->selectHydrator, + 'connectionName' => $queryData['connectionName'], + 'config' => $queryData['config'] + ] + ); + } + $query = $this->constructQuery($queryName); + $this->queryCache->save(json_encode($query), $queryName); + return $query; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/ReportProvider.php b/app/code/Magento/Analytics/ReportXml/ReportProvider.php new file mode 100644 index 0000000000000..4edd1100c5325 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/ReportProvider.php @@ -0,0 +1,83 @@ +queryFactory = $queryFactory; + $this->connectionFactory = $connectionFactory; + $this->iteratorFactory = $iteratorFactory; + } + + /** + * Returns custom iterator name for report + * Null for default + * + * @param Query $query + * @return string|null + * @since 2.2.0 + */ + private function getIteratorName(Query $query) + { + $config = $query->getConfig(); + return isset($config['iterator']) ? $config['iterator'] : null; + } + + /** + * Returns report data by name and criteria + * + * @param string $name + * @return \IteratorIterator + * @since 2.2.0 + */ + public function getReport($name) + { + $query = $this->queryFactory->create($name); + $connection = $this->connectionFactory->getConnection($query->getConnectionName()); + $statement = $connection->query($query->getSelect()); + return $this->iteratorFactory->create($statement, $this->getIteratorName($query)); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/SelectHydrator.php b/app/code/Magento/Analytics/ReportXml/SelectHydrator.php new file mode 100644 index 0000000000000..9dd0f8327dd14 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/SelectHydrator.php @@ -0,0 +1,153 @@ +resourceConnection = $resourceConnection; + $this->objectManager = $objectManager; + $this->selectParts = $selectParts; + } + + /** + * @return array + * @since 2.2.0 + */ + private function getSelectParts() + { + return array_merge($this->predefinedSelectParts, $this->selectParts); + } + + /** + * Extracts Select metadata parts + * + * @param Select $select + * @return array + * @throws \Zend_Db_Select_Exception + * @since 2.2.0 + */ + public function extract(Select $select) + { + $parts = []; + foreach ($this->getSelectParts() as $partName) { + $parts[$partName] = $select->getPart($partName); + } + return $parts; + } + + /** + * @param array $selectParts + * @return Select + * @since 2.2.0 + */ + public function recreate(array $selectParts) + { + $select = $this->resourceConnection->getConnection()->select(); + + $select = $this->processColumns($select, $selectParts); + + foreach ($selectParts as $partName => $partValue) { + $select->setPart($partName, $partValue); + } + + return $select; + } + + /** + * Process COLUMNS part values and add this part into select. + * + * If each column contains information about select expression + * an object with the type of this expression going to be created and assigned to this column. + * + * @param Select $select + * @param array $selectParts + * @return Select + * @since 2.2.0 + */ + private function processColumns(Select $select, array &$selectParts) + { + if (!empty($selectParts[Select::COLUMNS]) && is_array($selectParts[Select::COLUMNS])) { + $part = []; + + foreach ($selectParts[Select::COLUMNS] as $columnEntry) { + list($correlationName, $column, $alias) = $columnEntry; + if (is_array($column) && !empty($column['class'])) { + $expression = $this->objectManager->create( + $column['class'], + isset($column['arguments']) ? $column['arguments'] : [] + ); + $part[] = [$correlationName, $expression, $alias]; + } else { + $part[] = $columnEntry; + } + } + + $select->setPart(Select::COLUMNS, $part); + unset($selectParts[Select::COLUMNS]); + } + + return $select; + } +} diff --git a/app/code/Magento/Analytics/Setup/InstallData.php b/app/code/Magento/Analytics/Setup/InstallData.php new file mode 100644 index 0000000000000..302cf00f9091f --- /dev/null +++ b/app/code/Magento/Analytics/Setup/InstallData.php @@ -0,0 +1,47 @@ +notificationTime = $notificationTime; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @since 2.2.0 + */ + public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + { + $this->notificationTime->storeLastTimeNotification(1); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php new file mode 100644 index 0000000000000..b94a295c86527 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php @@ -0,0 +1,76 @@ +abstractElementMock = $this->getMockBuilder(AbstractElement::class) + ->setMethods(['getComment', 'getLabel']) + ->disableOriginalConstructor() + ->getMock(); + $this->contextMock = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->getMock(); + $this->formMock = $this->getMockBuilder(Form::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->additionalComment = new AdditionalComment($this->contextMock); + } + + /** + * @return void + */ + public function testRender() + { + $this->abstractElementMock->setForm($this->formMock); + $this->abstractElementMock->expects($this->any()) + ->method('getComment') + ->willReturn('New comment'); + $this->abstractElementMock->expects($this->any()) + ->method('getLabel') + ->willReturn('Comment label'); + $html = $this->additionalComment->render($this->abstractElementMock); + $this->assertRegexp( + "/New comment/", + $html + ); + $this->assertRegexp( + "/Comment label/", + $html + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php new file mode 100644 index 0000000000000..d37daf9525119 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php @@ -0,0 +1,79 @@ +abstractElementMock = $this->getMockBuilder(AbstractElement::class) + ->setMethods(['getComment']) + ->disableOriginalConstructor() + ->getMock(); + $this->contextMock = $this->getMockBuilder(Context::class) + ->setMethods(['getLocaleDate']) + ->disableOriginalConstructor() + ->getMock(); + $this->formMock = $this->getMockBuilder(Form::class) + ->disableOriginalConstructor() + ->getMock(); + $this->timeZoneMock = $this->getMockBuilder(TimezoneInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->contextMock->expects($this->any()) + ->method('getLocaleDate') + ->willReturn($this->timeZoneMock); + $this->collectionTimeLabel = new CollectionTimeLabel($this->contextMock); + } + + /** + * @return void + */ + public function testRender() + { + $timeZone = "America/New_York"; + $this->abstractElementMock->setForm($this->formMock); + $this->timeZoneMock->expects($this->once()) + ->method('getConfigTimezone') + ->willReturn($timeZone); + $this->abstractElementMock->expects($this->any()) + ->method('getComment') + ->willReturn('Eastern Standard Time (America/New_York)'); + $this->assertRegexp( + "/Eastern Standard Time \(America\/New_York\)/", + $this->collectionTimeLabel->render($this->abstractElementMock) + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php new file mode 100644 index 0000000000000..e25e745317699 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php @@ -0,0 +1,86 @@ +subscriptionStatusProviderMock = $this->getMockBuilder(SubscriptionStatusProvider::class) + ->disableOriginalConstructor() + ->getMock(); + $this->contextMock = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->getMock(); + $this->abstractElementMock = $this->getMockBuilder(AbstractElement::class) + ->setMethods(['getComment']) + ->disableOriginalConstructor() + ->getMock(); + $this->formMock = $this->getMockBuilder(Form::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->subscriptionStatusLabel = new SubscriptionStatusLabel( + $this->contextMock, + $this->subscriptionStatusProviderMock + ); + } + + /** + * @return void + */ + public function testRender() + { + $this->abstractElementMock->setForm($this->formMock); + $this->subscriptionStatusProviderMock->expects($this->once()) + ->method('getStatus') + ->willReturn('Enabled'); + $this->abstractElementMock->expects($this->any()) + ->method('getComment') + ->willReturn('Subscription status: Enabled'); + $this->assertRegexp( + "/Subscription status: Enabled/", + $this->subscriptionStatusLabel->render($this->abstractElementMock) + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php new file mode 100644 index 0000000000000..3a251f9a8685a --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php @@ -0,0 +1,84 @@ +configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resultRedirectFactoryMock = $this->getMockBuilder(RedirectFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->redirectMock = $this->getMockBuilder(Redirect::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->signUpController = $this->objectManagerHelper->getObject( + SignUp::class, + [ + 'config' => $this->configMock, + 'resultRedirectFactory' => $this->resultRedirectFactoryMock + ] + ); + } + + /** + * @return void + */ + public function testExecute() + { + $urlBIEssentialsConfigPath = 'analytics/url/bi_essentials'; + $this->configMock->expects($this->once()) + ->method('getValue') + ->with($urlBIEssentialsConfigPath) + ->willReturn('value'); + $this->resultRedirectFactoryMock->expects($this->once())->method('create')->willReturn($this->redirectMock); + $this->redirectMock->expects($this->once())->method('setUrl')->with('value')->willReturnSelf(); + $this->assertEquals($this->redirectMock, $this->signUpController->execute()); + } +} 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 new file mode 100644 index 0000000000000..99de92cc63905 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Reports/ShowTest.php @@ -0,0 +1,185 @@ +reportUrlProviderMock = $this->getMockBuilder(ReportUrlProvider::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->redirectMock = $this->getMockBuilder(Redirect::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->messageManagerMock = $this->getMockBuilder(ManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->showController = $this->objectManagerHelper->getObject( + Show::class, + [ + 'reportUrlProvider' => $this->reportUrlProviderMock, + 'resultFactory' => $this->resultFactoryMock, + 'messageManager' => $this->messageManagerMock, + ] + ); + } + + /** + * @return void + */ + public function testExecute() + { + $otpUrl = 'http://example.com?otp=15vbjcfdvd15645'; + + $this->resultFactoryMock + ->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_REDIRECT) + ->willReturn($this->redirectMock); + $this->reportUrlProviderMock + ->expects($this->once()) + ->method('getUrl') + ->with() + ->willReturn($otpUrl); + $this->redirectMock + ->expects($this->once()) + ->method('setUrl') + ->with($otpUrl) + ->willReturnSelf(); + $this->assertSame($this->redirectMock, $this->showController->execute()); + } + + /** + * @dataProvider executeWithExceptionDataProvider + * + * @param \Exception $exception + */ + public function testExecuteWithException(\Exception $exception) + { + + $this->resultFactoryMock + ->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_REDIRECT) + ->willReturn($this->redirectMock); + $this->reportUrlProviderMock + ->expects($this->once()) + ->method('getUrl') + ->with() + ->willThrowException($exception); + if ($exception instanceof LocalizedException) { + $message = $exception->getMessage(); + } else { + $message = __('Sorry, there has been an error processing your request. Please try again later.'); + } + $this->messageManagerMock + ->expects($this->once()) + ->method('addExceptionMessage') + ->with($exception, $message) + ->willReturnSelf(); + $this->redirectMock + ->expects($this->once()) + ->method('setPath') + ->with('adminhtml') + ->willReturnSelf(); + $this->assertSame($this->redirectMock, $this->showController->execute()); + } + + /** + * @return array + */ + public function executeWithExceptionDataProvider() + { + return [ + 'ExecuteWithLocalizedException' => [new LocalizedException(__('TestMessage'))], + '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/Controller/Adminhtml/Subscription/ActivateTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php new file mode 100644 index 0000000000000..9097349e9137c --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php @@ -0,0 +1,252 @@ +resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->resultJsonMock = $this->getMockBuilder(Json::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->preparedValueFactoryMock = $this->getMockBuilder(PreparedValueFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configValueResourceMock = $this->getMockBuilder(AbstractDb::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->requestMock = $this->getMockBuilder(RequestInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->activateController = $this->objectManagerHelper->getObject( + Activate::class, + [ + 'resultFactory' => $this->resultFactoryMock, + 'preparedValueFactory' => $this->preparedValueFactoryMock, + 'configValueResource' => $this->configValueResourceMock, + 'logger' => $this->loggerMock, + 'notificationTime' => $this->notificationTimeMock, + '_request' => $this->requestMock, + 'subscriptionApprovedFiled' => $this->subscriptionApprovedField, + ] + ); + } + + /** + * @dataProvider executeDataProvider + * + * @param bool $isSubscriptionEnabled + * @return void + */ + public function testExecute($isSubscriptionEnabled) + { + $successResult = [ + 'success' => true, + 'error_message' => '', + ]; + + $this->requestMock + ->expects($this->once()) + ->method('getParam') + ->with($this->subscriptionApprovedField) + ->willReturn($isSubscriptionEnabled); + + if ($isSubscriptionEnabled) { + $configValue = $this->createConfigValueMock(); + $this->preparedValueFactoryMock + ->expects($this->once()) + ->method('create') + ->willReturn($configValue); + $this->configValueResourceMock->expects($this->once())->method('save')->with($configValue); + } else { + $this->notificationTimeMock + ->expects($this->once()) + ->method('unsetLastTimeNotificationValue') + ->willReturn(true); + } + + $this->resultFactoryMock->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_JSON) + ->willReturn($this->resultJsonMock); + $this->resultJsonMock->expects($this->once()) + ->method('setData') + ->with($successResult) + ->willReturnSelf(); + $this->assertSame( + $this->resultJsonMock, + $this->activateController->execute() + ); + } + + /** + * @dataProvider executeExceptionsDataProvider + * + * @param \Exception $exception + */ + public function testExecuteWithException(\Exception $exception) + { + $this->requestMock + ->expects($this->once()) + ->method('getParam') + ->with($this->subscriptionApprovedField) + ->willReturn(true); + + $this->preparedValueFactoryMock + ->expects($this->once()) + ->method('create') + ->willThrowException($exception); + $this->loggerMock + ->expects($this->once()) + ->method('error') + ->with($exception->getMessage()); + $this->resultFactoryMock + ->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_JSON) + ->willReturn($this->resultJsonMock); + + if ($exception instanceof LocalizedException) { + $this->resultJsonMock + ->expects($this->once()) + ->method('setData') + ->with([ + 'success' => false, + 'error_message' => $exception->getMessage(), + ]) + ->willReturnSelf(); + } else { + $this->resultJsonMock + ->expects($this->once()) + ->method('setData') + ->withAnyParameters() + ->willReturnSelf(); + } + + $this->assertSame( + $this->resultJsonMock, + $this->activateController->execute() + ); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function createConfigValueMock() + { + return $this->getMockBuilder(\Magento\Framework\Model\AbstractModel::class) + ->disableOriginalConstructor() + ->getMock(); + } + + /** + * @return array + */ + public function executeExceptionsDataProvider() + { + return [ + [new LocalizedException(__('TestMessage'))], + [new \Exception('TestMessage')], + ]; + } + + /** + * @return array + */ + public function executeDataProvider() + { + return [ + [true], + [false], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php new file mode 100644 index 0000000000000..0f425291bf999 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php @@ -0,0 +1,168 @@ +dateTimeFactoryMock = $this->getMockBuilder(DateTimeFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->dateTimeMock = $this->getMockBuilder(\DateTime::class) + ->disableOriginalConstructor() + ->getMock(); + $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) + ->disableOriginalConstructor() + ->getMock(); + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->getMock(); + $this->resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resultMock = $this->getMockBuilder(Json::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resultFactoryMock->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_JSON) + ->willReturn($this->resultMock); + $objectManagerHelper = new ObjectManagerHelper($this); + $this->action = $objectManagerHelper->getObject( + Postpone::class, + [ + 'resultFactory' => $this->resultFactoryMock, + 'dateTimeFactory' => $this->dateTimeFactoryMock, + 'notificationTime' => $this->notificationTimeMock, + 'logger' => $this->loggerMock + ] + ); + } + + public function testExecuteSuccess() + { + $this->dateTimeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->dateTimeMock); + $this->dateTimeMock->expects($this->once()) + ->method('getTimestamp') + ->willReturn(100500); + $this->notificationTimeMock->expects($this->once()) + ->method('storeLastTimeNotification') + ->with(100500) + ->willReturn(true); + $this->resultMock->expects($this->once()) + ->method('setData') + ->with( + [ + 'success' => true, + 'error_message' => '' + ], + false, + [] + )->willReturnSelf(); + $this->assertEquals($this->resultMock, $this->action->execute()); + } + + public function testExecuteFailedWithLocalizedException() + { + $this->dateTimeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->dateTimeMock); + $this->dateTimeMock->expects($this->once()) + ->method('getTimestamp') + ->willReturn(100500); + $this->notificationTimeMock->expects($this->once()) + ->method('storeLastTimeNotification') + ->with(100500) + ->willThrowException(new LocalizedException(__('Error message'))); + $this->resultMock->expects($this->once()) + ->method('setData') + ->with( + [ + 'success' => false, + 'error_message' => 'Error message' + ], + false, + [] + )->willReturnSelf(); + $this->assertEquals($this->resultMock, $this->action->execute()); + } + + public function testExecuteFailedWithException() + { + $this->dateTimeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->dateTimeMock); + $this->dateTimeMock->expects($this->once()) + ->method('getTimestamp') + ->willReturn(100500); + $this->notificationTimeMock->expects($this->once()) + ->method('storeLastTimeNotification') + ->with(100500) + ->willThrowException(new \Exception('Any message')); + $this->resultMock->expects($this->once()) + ->method('setData') + ->with( + [ + 'success' => false, + 'error_message' => __('Error occurred during postponement notification') + ], + false, + [] + )->willReturnSelf(); + $this->assertEquals($this->resultMock, $this->action->execute()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php new file mode 100644 index 0000000000000..2c921e2260140 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php @@ -0,0 +1,159 @@ +resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->resultRedirectMock = $this->getMockBuilder(Redirect::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->subscriptionHandlerMock = $this->getMockBuilder(SubscriptionHandler::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->messageManagerMock = $this->getMockBuilder(ManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->retryController = $this->objectManagerHelper->getObject( + Retry::class, + [ + 'resultFactory' => $this->resultFactoryMock, + 'subscriptionHandler' => $this->subscriptionHandlerMock, + 'messageManager' => $this->messageManagerMock, + ] + ); + } + + /** + * @return void + */ + public function testExecute() + { + $this->resultFactoryMock + ->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_REDIRECT) + ->willReturn($this->resultRedirectMock); + $this->resultRedirectMock + ->expects($this->once()) + ->method('setPath') + ->with('adminhtml') + ->willReturnSelf(); + $this->subscriptionHandlerMock + ->expects($this->once()) + ->method('processEnabled') + ->with() + ->willReturn(true); + $this->assertSame( + $this->resultRedirectMock, + $this->retryController->execute() + ); + } + + /** + * @dataProvider executeExceptionsDataProvider + * + * @param \Exception $exception + * @param Phrase $message + */ + public function testExecuteWithException(\Exception $exception, Phrase $message) + { + $this->resultFactoryMock + ->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_REDIRECT) + ->willReturn($this->resultRedirectMock); + $this->resultRedirectMock + ->expects($this->once()) + ->method('setPath') + ->with('adminhtml') + ->willReturnSelf(); + $this->subscriptionHandlerMock + ->expects($this->once()) + ->method('processEnabled') + ->with() + ->willThrowException($exception); + $this->messageManagerMock + ->expects($this->once()) + ->method('addExceptionMessage') + ->with($exception, $message); + + $this->assertSame( + $this->resultRedirectMock, + $this->retryController->execute() + ); + } + + /** + * @return array + */ + public function executeExceptionsDataProvider() + { + return [ + [new LocalizedException(__('TestMessage')), __('TestMessage')], + [ + new \Exception('TestMessage'), + __('Sorry, there has been an error processing your request. Please try again later.') + ], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php b/app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php new file mode 100644 index 0000000000000..ef071cdf3a911 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php @@ -0,0 +1,91 @@ +exportDataHandlerMock = $this->getMockBuilder(ExportDataHandlerInterface::class) + ->getMockForAbstractClass(); + + $this->subscriptionStatusMock = $this->getMockBuilder(SubscriptionStatusProvider::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->collectData = $this->objectManagerHelper->getObject( + CollectData::class, + [ + 'exportDataHandler' => $this->exportDataHandlerMock, + 'subscriptionStatus' => $this->subscriptionStatusMock, + ] + ); + } + + /** + * @param string $status + * @return void + * @dataProvider executeDataProvider + */ + public function testExecute($status) + { + $this->subscriptionStatusMock + ->expects($this->once()) + ->method('getStatus') + ->with() + ->willReturn($status); + $this->exportDataHandlerMock + ->expects(($status === SubscriptionStatusProvider::ENABLED) ? $this->once() : $this->never()) + ->method('prepareExportData') + ->with(); + + $this->assertTrue($this->collectData->execute()); + } + + /** + * @return array + */ + public function executeDataProvider() + { + return [ + 'Subscription is enabled' => [SubscriptionStatusProvider::ENABLED], + 'Subscription is disabled' => [SubscriptionStatusProvider::DISABLED], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php new file mode 100644 index 0000000000000..c8ab5a6f4649e --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php @@ -0,0 +1,133 @@ +connectorMock = $this->getMockBuilder(Connector::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configWriterMock = $this->getMockBuilder(WriterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->reinitableConfigMock = $this->getMockBuilder(ReinitableConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->signUp = new SignUp( + $this->connectorMock, + $this->configWriterMock, + $this->flagManagerMock, + $this->reinitableConfigMock + ); + } + + public function testExecute() + { + $attemptsCount = 10; + + $this->flagManagerMock->expects($this->once()) + ->method('getFlagData') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE) + ->willReturn($attemptsCount); + + $attemptsCount -= 1; + $this->flagManagerMock->expects($this->once()) + ->method('saveFlag') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, $attemptsCount); + $this->connectorMock->expects($this->once()) + ->method('execute') + ->with('signUp') + ->willReturn(true); + $this->addDeleteAnalyticsCronExprAsserts(); + $this->flagManagerMock->expects($this->once()) + ->method('deleteFlag') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + $this->assertTrue($this->signUp->execute()); + } + + public function testExecuteFlagNotExist() + { + $this->flagManagerMock->expects($this->once()) + ->method('getFlagData') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE) + ->willReturn(null); + $this->addDeleteAnalyticsCronExprAsserts(); + $this->assertFalse($this->signUp->execute()); + } + + public function testExecuteZeroAttempts() + { + $attemptsCount = 0; + $this->flagManagerMock->expects($this->once()) + ->method('getFlagData') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE) + ->willReturn($attemptsCount); + $this->addDeleteAnalyticsCronExprAsserts(); + $this->flagManagerMock->expects($this->once()) + ->method('deleteFlag') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + $this->assertFalse($this->signUp->execute()); + } + + /** + * Add assertions for method deleteAnalyticsCronExpr. + * + * @return void + */ + private function addDeleteAnalyticsCronExprAsserts() + { + $this->configWriterMock + ->expects($this->once()) + ->method('delete') + ->with(SubscriptionHandler::CRON_STRING_PATH) + ->willReturn(true); + $this->reinitableConfigMock + ->expects($this->once()) + ->method('reinit') + ->willReturnSelf(); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php b/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php new file mode 100644 index 0000000000000..23ba59a90ce7b --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php @@ -0,0 +1,214 @@ +connectorMock = $this->getMockBuilder(Connector::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configWriterMock = $this->getMockBuilder(WriterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + $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->analyticsTokenMock + ); + } + + /** + * @return void + */ + public function testExecuteWithoutToken() + { + $this->flagManagerMock + ->method('getFlagData') + ->with(SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE) + ->willReturn(10); + $this->connectorMock + ->expects($this->once()) + ->method('execute') + ->with('update') + ->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') + ->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(); + } + + /** + * @param $counterData + * @return void + * @dataProvider executeWithEmptyReverseCounterDataProvider + */ + public function testExecuteWithEmptyReverseCounter($counterData) + { + $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/AnalyticsTokenTest.php b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php new file mode 100644 index 0000000000000..e078bbe99f93a --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php @@ -0,0 +1,129 @@ +reinitableConfigMock = $this->getMockBuilder(ReinitableConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configWriterMock = $this->getMockBuilder(WriterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->tokenModel = $this->objectManagerHelper->getObject( + AnalyticsToken::class, + [ + 'reinitableConfig' => $this->reinitableConfigMock, + 'config' => $this->configMock, + 'configWriter' => $this->configWriterMock, + 'tokenPath' => $this->tokenPath, + ] + ); + } + + /** + * @return void + */ + public function testStoreToken() + { + $value = 'jjjj0000'; + + $this->configWriterMock + ->expects($this->once()) + ->method('save') + ->with($this->tokenPath, $value); + + $this->reinitableConfigMock + ->expects($this->once()) + ->method('reinit') + ->willReturnSelf(); + + $this->assertTrue($this->tokenModel->storeToken($value)); + } + + /** + * @return void + */ + public function testGetToken() + { + $value = 'jjjj0000'; + + $this->configMock + ->expects($this->once()) + ->method('getValue') + ->with($this->tokenPath) + ->willReturn($value); + + $this->assertSame($value, $this->tokenModel->getToken()); + } + + /** + * @return void + */ + public function testIsTokenExist() + { + $this->assertFalse($this->tokenModel->isTokenExist()); + + $this->configMock + ->expects($this->once()) + ->method('getValue') + ->with($this->tokenPath) + ->willReturn('0000'); + $this->assertTrue($this->tokenModel->isTokenExist()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php new file mode 100644 index 0000000000000..bfdc971efc79e --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -0,0 +1,81 @@ +dateTimeFactoryMock = $this->getMockBuilder(DateTimeFactory::class) + ->getMock(); + $this->dateTimeMock = $this->getMockBuilder(\DateTime::class) + ->getMock(); + $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManager = new ObjectManager($this); + $this->canViewNotification = $objectManager->getObject( + CanViewNotification::class, + [ + 'notificationTime' => $this->notificationTimeMock, + 'dateTimeFactory' => $this->dateTimeFactoryMock + ] + ); + } + + public function testValidate() + { + $this->notificationTimeMock->expects($this->once()) + ->method('getLastTimeNotification') + ->willReturn(1); + $this->dateTimeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->dateTimeMock); + $this->dateTimeMock->expects($this->once()) + ->method('getTimestamp') + ->willReturn(10005000); + $this->assertTrue($this->canViewNotification->isVisible([])); + } + + public function testValidateFlagRemoved() + { + $this->notificationTimeMock->expects($this->once()) + ->method('getLastTimeNotification') + ->willReturn(null); + $this->dateTimeFactoryMock->expects($this->never()) + ->method('create'); + $this->assertFalse($this->canViewNotification->isVisible([])); + } +} 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/Config/Backend/CollectionTimeTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/CollectionTimeTest.php new file mode 100644 index 0000000000000..555020ffd247f --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/CollectionTimeTest.php @@ -0,0 +1,111 @@ +configWriterMock = $this->getMockBuilder(WriterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->collectionTime = $this->objectManagerHelper->getObject( + CollectionTime::class, + [ + 'configWriter' => $this->configWriterMock, + '_logger' => $this->loggerMock, + ] + ); + } + + /** + * @return void + */ + public function testAfterSave() + { + $this->collectionTime->setData('value', '05,04,03'); + + $this->configWriterMock + ->expects($this->once()) + ->method('save') + ->with(CollectionTime::CRON_SCHEDULE_PATH, join(' ', ['04', '05', '*', '*', '*'])); + + $this->assertInstanceOf( + Value::class, + $this->collectionTime->afterSave() + ); + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testAfterSaveWrongValue() + { + $this->collectionTime->setData('value', '00,01'); + $this->collectionTime->afterSave(); + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testAfterSaveWithLocalizedException() + { + $exception = new \Exception('Test message'); + $this->collectionTime->setData('value', '05,04,03'); + + $this->configWriterMock + ->expects($this->once()) + ->method('save') + ->with(CollectionTime::CRON_SCHEDULE_PATH, join(' ', ['04', '05', '*', '*', '*'])) + ->willThrowException($exception); + $this->loggerMock + ->expects($this->once()) + ->method('error') + ->with($exception->getMessage()); + $this->collectionTime->afterSave(); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php new file mode 100644 index 0000000000000..d01101bf5cc3b --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php @@ -0,0 +1,185 @@ +flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configWriterMock = $this->getMockBuilder(WriterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->tokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->subscriptionHandler = $this->objectManagerHelper->getObject( + SubscriptionHandler::class, + [ + 'flagManager' => $this->flagManagerMock, + 'configWriter' => $this->configWriterMock, + 'attemptsInitValue' => $this->attemptsInitValue, + 'analyticsToken' => $this->tokenMock, + 'notificationTime' => $this->notificationTimeMock, + ] + ); + } + + /** + * @return void + */ + public function testProcessEnabledTokenExist() + { + $this->tokenMock + ->expects($this->once()) + ->method('isTokenExist') + ->willReturn(true); + $this->configWriterMock + ->expects($this->never()) + ->method('save'); + $this->flagManagerMock + ->expects($this->never()) + ->method('saveFlag'); + $this->notificationTimeMock + ->expects($this->never()) + ->method('unsetLastTimeNotificationValue'); + $this->assertTrue( + $this->subscriptionHandler->processEnabled() + ); + } + + /** + * @return void + */ + public function testProcessEnabledTokenDoesNotExist() + { + $this->tokenMock + ->expects($this->once()) + ->method('isTokenExist') + ->willReturn(false); + $this->configWriterMock + ->expects($this->once()) + ->method('save') + ->with(SubscriptionHandler::CRON_STRING_PATH, "0 * * * *"); + $this->flagManagerMock + ->expects($this->once()) + ->method('saveFlag') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, $this->attemptsInitValue) + ->willReturn(true); + $this->notificationTimeMock + ->expects($this->once()) + ->method('unsetLastTimeNotificationValue') + ->willReturn(true); + $this->assertTrue( + $this->subscriptionHandler->processEnabled() + ); + } + + /** + * @return void + */ + public function testProcessDisabledTokenDoesNotExist() + { + $this->configWriterMock + ->expects($this->once()) + ->method('delete') + ->with(CollectionTime::CRON_SCHEDULE_PATH); + $this->tokenMock + ->expects($this->once()) + ->method('isTokenExist') + ->willReturn(false); + $this->flagManagerMock + ->expects($this->once()) + ->method('deleteFlag') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE) + ->willReturn(true); + $this->assertTrue( + $this->subscriptionHandler->processDisabled() + ); + } + + /** + * @return void + */ + public function testProcessDisabledTokenExists() + { + $this->configWriterMock + ->expects($this->once()) + ->method('delete') + ->with(CollectionTime::CRON_SCHEDULE_PATH); + $this->tokenMock + ->expects($this->once()) + ->method('isTokenExist') + ->willReturn(true); + $this->flagManagerMock + ->expects($this->never()) + ->method('deleteFlag'); + $this->assertTrue( + $this->subscriptionHandler->processDisabled() + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php new file mode 100644 index 0000000000000..d64827d2d18d2 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php @@ -0,0 +1,184 @@ +subscriptionHandlerMock = $this->getMockBuilder(SubscriptionHandler::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->enabledModel = $this->objectManagerHelper->getObject( + Enabled::class, + [ + 'subscriptionHandler' => $this->subscriptionHandlerMock, + '_logger' => $this->loggerMock, + 'config' => $this->configMock, + ] + ); + } + + /** + * @return void + */ + public function testAfterSaveSuccessEnabled() + { + $this->enabledModel->setData('value', $this->valueEnabled); + + $this->configMock + ->expects($this->any()) + ->method('getValue') + ->willReturn(!$this->valueEnabled); + + $this->subscriptionHandlerMock + ->expects($this->once()) + ->method('processEnabled') + ->with() + ->willReturn(true); + + $this->assertInstanceOf( + Value::class, + $this->enabledModel->afterSave() + ); + } + + /** + * @return void + */ + public function testAfterSaveSuccessDisabled() + { + $this->enabledModel->setData('value', $this->valueDisabled); + + $this->configMock + ->expects($this->any()) + ->method('getValue') + ->willReturn(!$this->valueDisabled); + + $this->subscriptionHandlerMock + ->expects($this->once()) + ->method('processDisabled') + ->with() + ->willReturn(true); + + $this->assertInstanceOf( + Value::class, + $this->enabledModel->afterSave() + ); + } + + /** + * @return void + */ + public function testAfterSaveSuccessValueNotChanged() + { + $this->enabledModel->setData('value', null); + + $this->configMock + ->expects($this->any()) + ->method('getValue') + ->willReturn(null); + + $this->subscriptionHandlerMock + ->expects($this->never()) + ->method('processEnabled') + ->with() + ->willReturn(true); + $this->subscriptionHandlerMock + ->expects($this->never()) + ->method('processDisabled') + ->with() + ->willReturn(true); + + $this->assertInstanceOf( + Value::class, + $this->enabledModel->afterSave() + ); + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testExecuteAfterSaveFailedWithLocalizedException() + { + $exception = new \Exception('Message'); + $this->enabledModel->setData('value', $this->valueEnabled); + + $this->subscriptionHandlerMock + ->expects($this->once()) + ->method('processEnabled') + ->with() + ->willThrowException($exception); + + $this->loggerMock + ->expects($this->once()) + ->method('error') + ->with($exception->getMessage()); + + $this->enabledModel->afterSave(); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php new file mode 100644 index 0000000000000..d689f040c48b3 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php @@ -0,0 +1,59 @@ +objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\Model\Config\Backend\Vertical::class + ); + } + + /** + * @return void + */ + public function testBeforeSaveSuccess() + { + $this->subject->setValue('Apps and Games'); + + $this->assertInstanceOf( + \Magento\Analytics\Model\Config\Backend\Vertical::class, + $this->subject->beforeSave() + ); + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testBeforeSaveFailedWithLocalizedException() + { + $this->subject->setValue(''); + + $this->subject->beforeSave(); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php new file mode 100644 index 0000000000000..7c94fb1b60a14 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php @@ -0,0 +1,142 @@ +objectManagerHelper = new ObjectManagerHelper($this); + + $this->mapper = $this->objectManagerHelper->getObject(Mapper::class); + } + + /** + * @param array $configData + * @param array $resultData + * @return void + * + * @dataProvider executingDataProvider + */ + public function testExecution($configData, $resultData) + { + $this->assertSame($resultData, $this->mapper->execute($configData)); + } + + /** + * @return array + */ + public function executingDataProvider() + { + return [ + 'wrongConfig' => [ + ['config' => ['files']], + [] + ], + 'validConfigWithFileNodes' => [ + [ + 'config' => [ + 0 => [ + 'file' => [ + 0 => [ + 'name' => 'fileName', + 'providers' => [[]] + ] + ] + ] + ] + ], + [ + 'fileName' => [ + 'name' => 'fileName', + 'providers' => [] + ] + ], + ], + 'validConfigWithProvidersNode' => [ + [ + 'config' => [ + 0 => [ + 'file' => [ + 0 => [ + 'name' => 'fileName', + 'providers' => [ + 0 => [ + 'reportProvider' => [0 => []] + ] + ] + ] + ] + ] + ] + ], + [ + 'fileName' => [ + 'name' => 'fileName', + 'providers' => [ + 'reportProvider' => ['parameters' => []] + ] + ] + ], + ], + 'validConfigWithParametersNode' => [ + [ + 'config' => [ + 0 => [ + 'file' => [ + 0 => [ + 'name' => 'fileName', + 'providers' => [ + 0 => [ + 'reportProvider' => [ + 0 => [ + 'parameters' => [ + 0 => ['name' => ['reportName']] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ], + [ + 'fileName' => [ + 'name' => 'fileName', + 'providers' => [ + 'reportProvider' => [ + 'parameters' => [ + 'name' => 'reportName' + ] + ] + ] + ] + ], + ], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php new file mode 100644 index 0000000000000..1eee74a1f93a0 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php @@ -0,0 +1,108 @@ +mapperMock = $this->getMockBuilder(Mapper::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->readerXmlMock = $this->getMockBuilder(ReaderInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->readerDbMock = $this->getMockBuilder(ReaderInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->reader = $this->objectManagerHelper->getObject( + Reader::class, + [ + 'mapper' => $this->mapperMock, + 'readers' => [ + $this->readerXmlMock, + $this->readerDbMock, + ], + ] + ); + } + + /** + * @return void + */ + public function testRead() + { + $scope = 'store'; + $xmlReaderResult = [ + 'config' => ['node1' => ['node2' => 'node4']] + ]; + $dbReaderResult = [ + 'config' => ['node1' => ['node2' => 'node3']] + ]; + $mapperResult = ['node2' => ['node3', 'node4']]; + + $this->readerXmlMock + ->expects($this->once()) + ->method('read') + ->with($scope) + ->willReturn($xmlReaderResult); + + $this->readerDbMock + ->expects($this->once()) + ->method('read') + ->with($scope) + ->willReturn($dbReaderResult); + + $this->mapperMock + ->expects($this->once()) + ->method('execute') + ->with(array_merge_recursive($xmlReaderResult, $dbReaderResult)) + ->willReturn($mapperResult); + + $this->assertSame($mapperResult, $this->reader->read($scope)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php new file mode 100644 index 0000000000000..b96f3543ff701 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php @@ -0,0 +1,60 @@ +objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\Model\Config\Source\Vertical::class, + [ + 'verticals' => [ + 'Apps and Games', + 'Athletic/Sporting Goods', + 'Art and Design' + ] + ] + ); + } + + /** + * @return void + */ + public function testToOptionArray() + { + $expectedOptionsArray = [ + ['value' => '', 'label' => __('--Please Select--')], + ['value' => 'Apps and Games', 'label' => __('Apps and Games')], + ['value' => 'Athletic/Sporting Goods', 'label' => __('Athletic/Sporting Goods')], + ['value' => 'Art and Design', 'label' => __('Art and Design')] + ]; + + $this->assertEquals( + $expectedOptionsArray, + $this->subject->toOptionArray() + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php new file mode 100644 index 0000000000000..8282b1ae52617 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php @@ -0,0 +1,68 @@ +dataInterfaceMock = $this->getMockBuilder(DataInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->config = $this->objectManagerHelper->getObject( + Config::class, + [ + 'data' => $this->dataInterfaceMock, + ] + ); + } + + /** + * @return void + */ + public function testGet() + { + $key = 'configKey'; + $defaultValue = 'mock'; + $configValue = 'emptyString'; + + $this->dataInterfaceMock + ->expects($this->once()) + ->method('get') + ->with($key, $defaultValue) + ->willReturn($configValue); + + $this->assertSame($configValue, $this->config->get($key, $defaultValue)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php new file mode 100644 index 0000000000000..6890fe200f9dc --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php @@ -0,0 +1,218 @@ +curlMock = $this->getMockBuilder( + \Magento\Framework\HTTP\Adapter\Curl::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockBuilder( + \Psr\Log\LoggerInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->curlFactoryMock = $this->getMockBuilder(CurlFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $this->curlFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($this->curlMock); + + $this->responseFactoryMock = $this->getMockBuilder( + \Magento\Analytics\Model\Connector\Http\ResponseFactory::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->converterMock = $this->createJsonConverter(); + + $this->objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\Model\Connector\Http\Client\Curl::class, + [ + 'curlFactory' => $this->curlFactoryMock, + 'responseFactory' => $this->responseFactoryMock, + 'converter' => $this->converterMock, + 'logger' => $this->loggerMock, + ] + ); + } + + /** + * Returns test parameters for request. + * + * @return array + */ + public function getTestData() + { + return [ + [ + 'data' => [ + 'version' => '1.1', + 'body'=> ['name' => 'value'], + 'url' => 'http://www.mystore.com', + 'headers' => [JsonConverter::CONTENT_TYPE_HEADER], + 'method' => \Magento\Framework\HTTP\ZendClient::POST, + ] + ] + ]; + } + + /** + * @return void + * @dataProvider getTestData + */ + public function testRequestSuccess(array $data) + { + $responseString = 'This is response.'; + $response = new \Zend_Http_Response(201, [], $responseString); + $this->curlMock->expects($this->once()) + ->method('write') + ->with( + $data['method'], + $data['url'], + $data['version'], + $data['headers'], + json_encode($data['body']) + ); + $this->curlMock->expects($this->once()) + ->method('read') + ->willReturn($responseString); + $this->curlMock->expects($this->any()) + ->method('getErrno') + ->willReturn(0); + + $this->responseFactoryMock->expects($this->any()) + ->method('create') + ->with($responseString) + ->willReturn($response); + + $this->assertEquals( + $response, + $this->subject->request( + $data['method'], + $data['url'], + $data['body'], + $data['headers'], + $data['version'] + ) + ); + } + + /** + * @return void + * @dataProvider getTestData + */ + public function testRequestError(array $data) + { + $response = new \Zend_Http_Response(0, []); + $this->curlMock->expects($this->once()) + ->method('write') + ->with( + $data['method'], + $data['url'], + $data['version'], + $data['headers'], + json_encode($data['body']) + ); + $this->curlMock->expects($this->once()) + ->method('read'); + $this->curlMock->expects($this->atLeastOnce()) + ->method('getErrno') + ->willReturn(1); + $this->curlMock->expects($this->atLeastOnce()) + ->method('getError') + ->willReturn('CURL error.'); + + $this->loggerMock->expects($this->once()) + ->method('critical') + ->with( + new \Exception( + 'MBI service CURL connection error #1: CURL error.' + ) + ); + + $this->assertEquals( + $response, + $this->subject->request( + $data['method'], + $data['url'], + $data['body'], + $data['headers'], + $data['version'] + ) + ); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function createJsonConverter() + { + $converterMock = $this->getMockBuilder(ConverterInterface::class) + ->getMockForAbstractClass(); + $converterMock->expects($this->any())->method('toBody')->willReturnCallback(function ($value) { + return json_encode($value); + }); + $converterMock->expects($this->any()) + ->method('getContentTypeHeader') + ->willReturn(JsonConverter::CONTENT_TYPE_HEADER); + return $converterMock; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php new file mode 100644 index 0000000000000..7ac6f50ea24c4 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php @@ -0,0 +1,34 @@ +assertEquals(JsonConverter::CONTENT_TYPE_HEADER, $converter->getContentTypeHeader()); + } + + public function testConvertBody() + { + $body = '{"token": "secret-token"}'; + $converter = new JsonConverter(); + $this->assertEquals(json_decode($body, 1), $converter->fromBody($body)); + } + + public function testConvertData() + { + $data = ["token" => "secret-token"]; + $converter = new JsonConverter(); + $this->assertEquals(json_encode($data), $converter->toBody($data)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php new file mode 100644 index 0000000000000..5047e8a9dd391 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php @@ -0,0 +1,39 @@ + 'testValue']; + $response = new \Zend_Http_Response(201, [], json_encode($expectedBody)); + $responseHandlerMock = $this->getMockBuilder(ResponseHandlerInterface::class) + ->getMockForAbstractClass(); + $responseHandlerMock->expects($this->once()) + ->method('handleResponse') + ->with($expectedBody) + ->willReturn(true); + $notFoundResponseHandlerMock = $this->getMockBuilder(ResponseHandlerInterface::class) + ->getMockForAbstractClass(); + $notFoundResponseHandlerMock->expects($this->never())->method('handleResponse'); + $responseResolver = new ResponseResolver( + new JsonConverter(), + [ + 201 => $responseHandlerMock, + 404 => $notFoundResponseHandlerMock, + ] + ); + $this->assertTrue($responseResolver->getResult($response)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php new file mode 100644 index 0000000000000..5b86dd6557d69 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php @@ -0,0 +1,107 @@ +analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->httpClientMock = $this->getMockBuilder(ClientInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $successHandler = $this->getMockBuilder(\Magento\Analytics\Model\Connector\Http\ResponseHandlerInterface::class) + ->getMockForAbstractClass(); + $successHandler->method('handleResponse') + ->willReturn(true); + + $this->notifyDataChangedCommand = new NotifyDataChangedCommand( + $this->analyticsTokenMock, + $this->httpClientMock, + $this->configMock, + new ResponseResolver(new JsonConverter(), [201 => $successHandler]), + $this->loggerMock + ); + } + + public function testExecuteSuccess() + { + $configVal = "Config val"; + $token = "Secret token!"; + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(true); + $this->configMock->expects($this->any()) + ->method('getValue') + ->willReturn($configVal); + $this->analyticsTokenMock->expects($this->once()) + ->method('getToken') + ->willReturn($token); + $this->httpClientMock->expects($this->once()) + ->method('request') + ->with( + ZendClient::POST, + $configVal, + ['access-token' => $token, 'url' => $configVal] + )->willReturn(new \Zend_Http_Response(201, [])); + $this->assertTrue($this->notifyDataChangedCommand->execute()); + } + + public function testExecuteWithoutToken() + { + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(false); + $this->httpClientMock->expects($this->never()) + ->method('request'); + $this->assertFalse($this->notifyDataChangedCommand->execute()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php new file mode 100644 index 0000000000000..a33d7d0d7c1bf --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php @@ -0,0 +1,187 @@ +loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->httpClientMock = $this->getMockBuilder(ClientInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->responseResolverMock = $this->getMockBuilder(ResponseResolver::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->subject = new OTPRequest( + $this->analyticsTokenMock, + $this->httpClientMock, + $this->configMock, + $this->responseResolverMock, + $this->loggerMock + ); + } + + /** + * Returns test parameters for request. + * + * @return array + */ + private function getTestData() + { + return [ + 'otp' => 'thisisotp', + 'url' => 'http://www.mystore.com', + 'access-token' => 'thisisaccesstoken', + 'method' => \Magento\Framework\HTTP\ZendClient::POST, + 'body'=> ['access-token' => 'thisisaccesstoken','url' => 'http://www.mystore.com'], + ]; + } + + /** + * @return void + */ + public function testCallSuccess() + { + $data = $this->getTestData(); + + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(true); + $this->analyticsTokenMock->expects($this->once()) + ->method('getToken') + ->willReturn($data['access-token']); + + $this->configMock->expects($this->any()) + ->method('getValue') + ->willReturn($data['url']); + + $this->httpClientMock->expects($this->once()) + ->method('request') + ->with( + $data['method'], + $data['url'], + $data['body'] + ) + ->willReturn(new \Zend_Http_Response(201, [])); + $this->responseResolverMock->expects($this->once()) + ->method('getResult') + ->willReturn($data['otp']); + + $this->assertEquals( + $data['otp'], + $this->subject->call() + ); + } + + /** + * @return void + */ + public function testCallNoAccessToken() + { + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(false); + + $this->httpClientMock->expects($this->never()) + ->method('request'); + + $this->assertFalse($this->subject->call()); + } + + /** + * @return void + */ + public function testCallNoOtp() + { + $data = $this->getTestData(); + + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(true); + $this->analyticsTokenMock->expects($this->once()) + ->method('getToken') + ->willReturn($data['access-token']); + + $this->configMock->expects($this->any()) + ->method('getValue') + ->willReturn($data['url']); + + $this->httpClientMock->expects($this->once()) + ->method('request') + ->with( + $data['method'], + $data['url'], + $data['body'] + ) + ->willReturn(new \Zend_Http_Response(0, [])); + + $this->responseResolverMock->expects($this->once()) + ->method('getResult') + ->willReturn(false); + + $this->loggerMock->expects($this->once()) + ->method('warning'); + + $this->assertFalse($this->subject->call()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php new file mode 100644 index 0000000000000..203eb57157e0e --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php @@ -0,0 +1,22 @@ +assertFalse($OTPHandler->handleResponse([])); + $expectedOtp = 123; + $this->assertEquals($expectedOtp, $OTPHandler->handleResponse(['otp' => $expectedOtp])); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php new file mode 100644 index 0000000000000..4c3dde7a92c3f --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php @@ -0,0 +1,36 @@ +getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + $analyticsToken->expects($this->once()) + ->method('storeToken') + ->with(null); + $subscriptionHandler = $this->getMockBuilder(SubscriptionHandler::class) + ->disableOriginalConstructor() + ->getMock(); + $subscriptionStatusProvider = $this->getMockBuilder(SubscriptionStatusProvider::class) + ->disableOriginalConstructor() + ->getMock(); + $subscriptionStatusProvider->method('getStatus')->willReturn(SubscriptionStatusProvider::ENABLED); + $reSignUpHandler = new ReSignUp($analyticsToken, $subscriptionHandler, $subscriptionStatusProvider); + $this->assertFalse($reSignUpHandler->handleResponse([])); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php new file mode 100644 index 0000000000000..2bbd528638a19 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php @@ -0,0 +1,30 @@ +getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + $analyticsToken->expects($this->once()) + ->method('storeToken') + ->with($accessToken); + $signUpHandler = new SignUp($analyticsToken, new JsonConverter()); + $this->assertFalse($signUpHandler->handleResponse([])); + $this->assertEquals($accessToken, $signUpHandler->handleResponse(['access-token' => $accessToken])); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php new file mode 100644 index 0000000000000..90102e2c3d868 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php @@ -0,0 +1,20 @@ +assertTrue($updateHandler->handleResponse([])); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php new file mode 100644 index 0000000000000..cc9eba99b3d48 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php @@ -0,0 +1,174 @@ +analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + $this->integrationManagerMock = $this->getMockBuilder(IntegrationManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->integrationToken = $this->getMockBuilder(IntegrationToken::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->httpClientMock = $this->getMockBuilder(ClientInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->responseResolverMock = $this->getMockBuilder(ResponseResolver::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->signUpCommand = new SignUpCommand( + $this->analyticsTokenMock, + $this->integrationManagerMock, + $this->configMock, + $this->httpClientMock, + $this->loggerMock, + $this->responseResolverMock + ); + } + + public function testExecuteSuccess() + { + $this->integrationManagerMock->expects($this->once()) + ->method('generateToken') + ->willReturn($this->integrationToken); + $this->integrationManagerMock->expects($this->once()) + ->method('activateIntegration') + ->willReturn(true); + $data = $this->getTestData(); + + $this->configMock->expects($this->any()) + ->method('getValue') + ->willReturn($data['url']); + $this->integrationToken->expects($this->any()) + ->method('getData') + ->with('token') + ->willReturn($data['integration-token']); + $httpResponse = new \Zend_Http_Response(201, [], '{"access-token": "' . $data['access-token'] . '"}'); + $this->httpClientMock->expects($this->once()) + ->method('request') + ->with( + $data['method'], + $data['url'], + $data['body'] + ) + ->willReturn($httpResponse); + $this->responseResolverMock->expects($this->any()) + ->method('getResult') + ->with($httpResponse) + ->willReturn(true); + $this->assertTrue($this->signUpCommand->execute()); + } + + public function testExecuteFailureCannotGenerateToken() + { + $this->integrationManagerMock->expects($this->once()) + ->method('generateToken') + ->willReturn(false); + $this->integrationManagerMock->expects($this->never()) + ->method('activateIntegration'); + $this->assertFalse($this->signUpCommand->execute()); + } + + public function testExecuteFailureResponseIsEmpty() + { + $this->integrationManagerMock->expects($this->once()) + ->method('generateToken') + ->willReturn($this->integrationToken); + $this->integrationManagerMock->expects($this->once()) + ->method('activateIntegration') + ->willReturn(true); + $httpResponse = new \Zend_Http_Response(0, []); + $this->httpClientMock->expects($this->once()) + ->method('request') + ->willReturn($httpResponse); + $this->responseResolverMock->expects($this->any()) + ->method('getResult') + ->willReturn(false); + $this->assertFalse($this->signUpCommand->execute()); + } + + /** + * Returns test parameters for request. + * + * @return array + */ + private function getTestData() + { + return [ + 'url' => 'http://www.mystore.com', + 'access-token' => 'thisisaccesstoken', + 'integration-token' => 'thisisintegrationtoken', + 'headers' => [JsonConverter::CONTENT_TYPE_HEADER], + 'method' => \Magento\Framework\HTTP\ZendClient::POST, + 'body'=> ['token' => 'thisisintegrationtoken','url' => 'http://www.mystore.com'], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php new file mode 100644 index 0000000000000..eb22461d789c8 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php @@ -0,0 +1,143 @@ +analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->httpClientMock = $this->getMockBuilder(ClientInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->responseResolverMock = $this->getMockBuilder(ResponseResolver::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->updateCommand = new UpdateCommand( + $this->analyticsTokenMock, + $this->httpClientMock, + $this->configMock, + $this->loggerMock, + $this->flagManagerMock, + $this->responseResolverMock + ); + } + + public function testExecuteSuccess() + { + $url = "old.localhost.com"; + $configVal = "Config val"; + $token = "Secret token!"; + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(true); + + $this->configMock->expects($this->any()) + ->method('getValue') + ->willReturn($configVal); + + $this->flagManagerMock->expects($this->once()) + ->method('getFlagData') + ->with(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE) + ->willReturn($url); + + $this->analyticsTokenMock->expects($this->once()) + ->method('getToken') + ->willReturn($token); + + $this->httpClientMock->expects($this->once()) + ->method('request') + ->with( + ZendClient::PUT, + $configVal, + [ + 'url' => $url, + 'new-url' => $configVal, + 'access-token' => $token + ] + )->willReturn(new \Zend_Http_Response(200, [])); + + $this->responseResolverMock->expects($this->once()) + ->method('getResult') + ->willReturn(true); + + $this->assertTrue($this->updateCommand->execute()); + } + + public function testExecuteWithoutToken() + { + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(false); + + $this->assertFalse($this->updateCommand->execute()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php new file mode 100644 index 0000000000000..14d641a19729d --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php @@ -0,0 +1,70 @@ +objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->signUpCommandMock = $this->getMockBuilder(SignUpCommand::class) + ->disableOriginalConstructor() + ->getMock(); + $this->commands = ['signUp' => SignUpCommand::class]; + $this->connector = new Connector($this->commands, $this->objectManagerMock); + } + + public function testExecute() + { + $commandName = 'signUp'; + $this->objectManagerMock->expects($this->once()) + ->method('create') + ->with($this->commands[$commandName]) + ->willReturn($this->signUpCommandMock); + $this->signUpCommandMock->expects($this->once()) + ->method('execute') + ->willReturn(true); + $this->assertTrue($this->connector->execute($commandName)); + } + + /** + * @expectedException \Magento\Framework\Exception\NotFoundException + */ + public function testExecuteCommandNotFound() + { + $commandName = 'register'; + $this->connector->execute($commandName); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php new file mode 100644 index 0000000000000..3de718d843a1d --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php @@ -0,0 +1,226 @@ +analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->encodedContextFactoryMock = $this->getMockBuilder(EncodedContextFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + + $this->encodedContextMock = $this->getMockBuilder(EncodedContext::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->key = ''; + $this->source = ''; + $this->initializationVectors = []; + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->cryptographer = $this->objectManagerHelper->getObject( + Cryptographer::class, + [ + 'analyticsToken' => $this->analyticsTokenMock, + 'encodedContextFactory' => $this->encodedContextFactoryMock, + 'cipherMethod' => $this->cipherMethod, + ] + ); + } + + /** + * @return void + */ + public function testEncode() + { + $token = 'some-token-value'; + $this->source = 'Some text'; + $this->key = hash('sha256', $token); + + $checkEncodedContext = function ($parameters) { + $emptyRequiredParameters = + array_diff(['content', 'initializationVector'], array_keys(array_filter($parameters))); + if ($emptyRequiredParameters) { + return false; + } + + $encryptedData = openssl_encrypt( + $this->source, + $this->cipherMethod, + $this->key, + OPENSSL_RAW_DATA, + $parameters['initializationVector'] + ); + + return ($encryptedData === $parameters['content']); + }; + + $this->analyticsTokenMock + ->expects($this->once()) + ->method('getToken') + ->with() + ->willReturn($token); + + $this->encodedContextFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->callback($checkEncodedContext)) + ->willReturn($this->encodedContextMock); + + $this->assertSame($this->encodedContextMock, $this->cryptographer->encode($this->source)); + } + + /** + * @return void + */ + public function testEncodeUniqueInitializationVector() + { + $this->source = 'Some text'; + $token = 'some-token-value'; + + $registerInitializationVector = function ($parameters) { + if (empty($parameters['initializationVector'])) { + return false; + } + + $this->initializationVectors[] = $parameters['initializationVector']; + + return true; + }; + + $this->analyticsTokenMock + ->expects($this->exactly(2)) + ->method('getToken') + ->with() + ->willReturn($token); + + $this->encodedContextFactoryMock + ->expects($this->exactly(2)) + ->method('create') + ->with($this->callback($registerInitializationVector)) + ->willReturn($this->encodedContextMock); + + $this->assertSame($this->encodedContextMock, $this->cryptographer->encode($this->source)); + $this->assertSame($this->encodedContextMock, $this->cryptographer->encode($this->source)); + $this->assertCount(2, array_unique($this->initializationVectors)); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @dataProvider encodeNotValidSourceDataProvider + */ + public function testEncodeNotValidSource($source) + { + $this->cryptographer->encode($source); + } + + /** + * @return array + */ + public function encodeNotValidSourceDataProvider() + { + return [ + 'Array' => [[]], + 'Empty string' => [''], + ]; + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testEncodeNotValidCipherMethod() + { + $source = 'Some string'; + $cryptographer = $this->objectManagerHelper->getObject( + Cryptographer::class, + [ + 'cipherMethod' => 'Wrong-method', + ] + ); + + $cryptographer->encode($source); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testEncodeTokenNotValid() + { + $source = 'Some string'; + + $this->analyticsTokenMock + ->expects($this->once()) + ->method('getToken') + ->with() + ->willReturn(null); + + $this->cryptographer->encode($source); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php b/app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php new file mode 100644 index 0000000000000..283b13212919d --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php @@ -0,0 +1,61 @@ +objectManagerHelper = new ObjectManagerHelper($this); + } + + /** + * @param string $content + * @param string|null $initializationVector + * @return void + * @dataProvider constructDataProvider + */ + public function testConstruct($content, $initializationVector) + { + $constructorArguments = [ + 'content' => $content, + 'initializationVector' => $initializationVector, + ]; + /** @var EncodedContext $encodedContext */ + $encodedContext = $this->objectManagerHelper->getObject( + EncodedContext::class, + array_filter($constructorArguments) + ); + + $this->assertSame($content, $encodedContext->getContent()); + $this->assertSame($initializationVector ?: '', $encodedContext->getInitializationVector()); + } + + /** + * @return array + */ + public function constructDataProvider() + { + return [ + 'Without Initialization Vector' => ['content text', null], + 'With Initialization Vector' => ['content text', 'c51sd3c4sd68c5sd'], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php new file mode 100644 index 0000000000000..b3826c232ed0c --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php @@ -0,0 +1,74 @@ +objectManagerHelper = new ObjectManagerHelper($this); + } + + /** + * @return void + */ + public function testThatNotifyExecuted() + { + $expectedResult = true; + $notifyCommandName = 'notifyDataChanged'; + $exportDataHandlerMockObject = $this->createExportDataHandlerMock(); + $analyticsConnectorMockObject = $this->createAnalyticsConnectorMock(); + /** + * @var $exportDataHandlerNotification ExportDataHandlerNotification + */ + $exportDataHandlerNotification = $this->objectManagerHelper->getObject( + ExportDataHandlerNotification::class, + [ + 'exportDataHandler' => $exportDataHandlerMockObject, + 'connector' => $analyticsConnectorMockObject, + ] + ); + $exportDataHandlerMockObject->expects($this->once()) + ->method('prepareExportData') + ->willReturn($expectedResult); + $analyticsConnectorMockObject->expects($this->once()) + ->method('execute') + ->with($notifyCommandName); + $this->assertEquals($expectedResult, $exportDataHandlerNotification->prepareExportData()); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function createExportDataHandlerMock() + { + return $this->getMockBuilder(ExportDataHandler::class)->disableOriginalConstructor()->getMock(); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function createAnalyticsConnectorMock() + { + return $this->getMockBuilder(Connector::class)->disableOriginalConstructor()->getMock(); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php new file mode 100644 index 0000000000000..7c181bea81aab --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php @@ -0,0 +1,270 @@ +filesystemMock = $this->getMockBuilder(Filesystem::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->archiveMock = $this->getMockBuilder(Archive::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->reportWriterMock = $this->getMockBuilder(ReportWriterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->cryptographerMock = $this->getMockBuilder(Cryptographer::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->fileRecorderMock = $this->getMockBuilder(FileRecorder::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->directoryMock = $this->getMockBuilder(WriteInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->encodedContextMock = $this->getMockBuilder(EncodedContext::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->exportDataHandler = $this->objectManagerHelper->getObject( + ExportDataHandler::class, + [ + 'filesystem' => $this->filesystemMock, + 'archive' => $this->archiveMock, + 'reportWriter' => $this->reportWriterMock, + 'cryptographer' => $this->cryptographerMock, + 'fileRecorder' => $this->fileRecorderMock, + 'subdirectoryPath' => $this->subdirectoryPath, + 'archiveName' => $this->archiveName, + ] + ); + } + + /** + * @param bool $isArchiveSourceDirectory + * @dataProvider prepareExportDataDataProvider + */ + public function testPrepareExportData($isArchiveSourceDirectory) + { + $tmpFilesDirectoryPath = $this->subdirectoryPath . 'tmp/'; + $archiveRelativePath = $this->subdirectoryPath . $this->archiveName; + + $archiveSource = $isArchiveSourceDirectory ? (__DIR__) : '/tmp/' . $tmpFilesDirectoryPath; + $archiveAbsolutePath = '/tmp/' . $archiveRelativePath; + + $this->filesystemMock + ->expects($this->once()) + ->method('getDirectoryWrite') + ->with(DirectoryList::SYS_TMP) + ->willReturn($this->directoryMock); + $this->directoryMock + ->expects($this->exactly(4)) + ->method('delete') + ->withConsecutive( + [$tmpFilesDirectoryPath], + [$archiveRelativePath] + ); + + $this->directoryMock + ->expects($this->exactly(4)) + ->method('getAbsolutePath') + ->withConsecutive( + [$tmpFilesDirectoryPath], + [$tmpFilesDirectoryPath], + [$archiveRelativePath], + [$archiveRelativePath] + ) + ->willReturnOnConsecutiveCalls( + $archiveSource, + $archiveSource, + $archiveAbsolutePath, + $archiveAbsolutePath + ); + + $this->reportWriterMock + ->expects($this->once()) + ->method('write') + ->with($this->directoryMock, $tmpFilesDirectoryPath); + + $this->directoryMock + ->expects($this->exactly(2)) + ->method('isExist') + ->withConsecutive( + [$tmpFilesDirectoryPath], + [$archiveRelativePath] + ) + ->willReturnOnConsecutiveCalls( + true, + true + ); + + $this->directoryMock + ->expects($this->once()) + ->method('create') + ->with(dirname($archiveRelativePath)); + + $this->archiveMock + ->expects($this->once()) + ->method('pack') + ->with( + $archiveSource, + $archiveAbsolutePath, + $isArchiveSourceDirectory ? true : false + ); + + $fileContent = 'Some text'; + $this->directoryMock + ->expects($this->once()) + ->method('readFile') + ->with($archiveRelativePath) + ->willReturn($fileContent); + + $this->cryptographerMock + ->expects($this->once()) + ->method('encode') + ->with($fileContent) + ->willReturn($this->encodedContextMock); + + $this->fileRecorderMock + ->expects($this->once()) + ->method('recordNewFile') + ->with($this->encodedContextMock); + + $this->assertTrue($this->exportDataHandler->prepareExportData()); + } + + /** + * @return array + */ + public function prepareExportDataDataProvider() + { + return [ + 'Data source for archive is directory' => [true], + 'Data source for archive doesn\'t directory' => [false], + ]; + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testPrepareExportDataWithLocalizedException() + { + $tmpFilesDirectoryPath = $this->subdirectoryPath . 'tmp/'; + $archivePath = $this->subdirectoryPath . $this->archiveName; + + $this->filesystemMock + ->expects($this->once()) + ->method('getDirectoryWrite') + ->with(DirectoryList::SYS_TMP) + ->willReturn($this->directoryMock); + $this->reportWriterMock + ->expects($this->once()) + ->method('write') + ->with($this->directoryMock, $tmpFilesDirectoryPath); + $this->directoryMock + ->expects($this->exactly(3)) + ->method('delete') + ->withConsecutive( + [$tmpFilesDirectoryPath], + [$tmpFilesDirectoryPath], + [$archivePath] + ); + $this->directoryMock + ->expects($this->exactly(2)) + ->method('getAbsolutePath') + ->with($tmpFilesDirectoryPath); + $this->directoryMock + ->expects($this->once()) + ->method('isExist') + ->with($tmpFilesDirectoryPath) + ->willReturn(false); + + $this->assertNull($this->exportDataHandler->prepareExportData()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php new file mode 100644 index 0000000000000..c8c07ae8240c3 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php @@ -0,0 +1,194 @@ +flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->fileInfoFactoryMock = $this->getMockBuilder(FileInfoFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + + $this->fileInfoMock = $this->getMockBuilder(FileInfo::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->fileInfoManager = $this->objectManagerHelper->getObject( + FileInfoManager::class, + [ + 'flagManager' => $this->flagManagerMock, + 'fileInfoFactory' => $this->fileInfoFactoryMock, + 'flagCode' => $this->flagCode, + 'encodedParameters' => $this->encodedParameters, + ] + ); + } + + /** + * @return void + */ + public function testSave() + { + $path = 'path/to/file'; + $initializationVector = openssl_random_pseudo_bytes(16); + $parameters = [ + 'path' => $path, + 'initializationVector' => $initializationVector, + ]; + + $this->fileInfoMock + ->expects($this->once()) + ->method('getPath') + ->with() + ->willReturn($path); + $this->fileInfoMock + ->expects($this->once()) + ->method('getInitializationVector') + ->with() + ->willReturn($initializationVector); + + foreach ($this->encodedParameters as $encodedParameter) { + $parameters[$encodedParameter] = base64_encode($parameters[$encodedParameter]); + } + $this->flagManagerMock + ->expects($this->once()) + ->method('saveFlag') + ->with($this->flagCode, $parameters); + + $this->assertTrue($this->fileInfoManager->save($this->fileInfoMock)); + } + + /** + * @param string|null $path + * @param string|null $initializationVector + * @dataProvider saveWithLocalizedExceptionDataProvider + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testSaveWithLocalizedException($path, $initializationVector) + { + $this->fileInfoMock + ->expects($this->once()) + ->method('getPath') + ->with() + ->willReturn($path); + $this->fileInfoMock + ->expects($this->once()) + ->method('getInitializationVector') + ->with() + ->willReturn($initializationVector); + + $this->fileInfoManager->save($this->fileInfoMock); + } + + /** + * @return array + */ + public function saveWithLocalizedExceptionDataProvider() + { + return [ + 'Empty FileInfo' => [null, null], + 'FileInfo without IV' => ['path/to/file', null], + ]; + } + + /** + * @dataProvider loadDataProvider + * @param array|null $parameters + */ + public function testLoad($parameters) + { + $this->flagManagerMock + ->expects($this->once()) + ->method('getFlagData') + ->with($this->flagCode) + ->willReturn($parameters); + + $processedParameters = $parameters ?: []; + $encodedParameters = array_intersect($this->encodedParameters, array_keys($processedParameters)); + foreach ($encodedParameters as $encodedParameter) { + $processedParameters[$encodedParameter] = base64_decode($processedParameters[$encodedParameter]); + } + + $this->fileInfoFactoryMock + ->expects($this->once()) + ->method('create') + ->with($processedParameters) + ->willReturn($this->fileInfoMock); + + $this->assertSame($this->fileInfoMock, $this->fileInfoManager->load()); + } + + /** + * @return array + */ + public function loadDataProvider() + { + return [ + 'Empty flag data' => [null], + 'Correct flag data' => [[ + 'path' => 'path/to/file', + 'initializationVector' => 'xUJjl54MVke+FvMFSBpRSA==', + ]], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php new file mode 100644 index 0000000000000..73f6ed644721a --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php @@ -0,0 +1,62 @@ +objectManagerHelper = new ObjectManagerHelper($this); + } + + /** + * @param string|null $path + * @param string|null $initializationVector + * @return void + * @dataProvider constructDataProvider + */ + public function testConstruct($path, $initializationVector) + { + $constructorArguments = [ + 'path' => $path, + 'initializationVector' => $initializationVector, + ]; + /** @var FileInfo $fileInfo */ + $fileInfo = $this->objectManagerHelper->getObject( + FileInfo::class, + array_filter($constructorArguments) + ); + + $this->assertSame($path ?: '', $fileInfo->getPath()); + $this->assertSame($initializationVector ?: '', $fileInfo->getInitializationVector()); + } + + /** + * @return array + */ + public function constructDataProvider() + { + return [ + 'Degenerate object' => [null, null], + 'Without Initialization Vector' => ['content text', null], + 'With Initialization Vector' => ['content text', 'c51sd3c4sd68c5sd'], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php new file mode 100644 index 0000000000000..68ff00a433fd2 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php @@ -0,0 +1,209 @@ +fileInfoManagerMock = $this->getMockBuilder(FileInfoManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->fileInfoFactoryMock = $this->getMockBuilder(FileInfoFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + + $this->filesystemMock = $this->getMockBuilder(Filesystem::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->fileInfoMock = $this->getMockBuilder(FileInfo::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->directoryMock = $this->getMockBuilder(WriteInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->encodedContextMock = $this->getMockBuilder(EncodedContext::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->fileRecorder = $this->objectManagerHelper->getObject( + FileRecorder::class, + [ + 'fileInfoManager' => $this->fileInfoManagerMock, + 'fileInfoFactory' => $this->fileInfoFactoryMock, + 'filesystem' => $this->filesystemMock, + 'fileSubdirectoryPath' => $this->fileSubdirectoryPath, + 'encodedFileName' => $this->encodedFileName, + ] + ); + } + + /** + * @param string $pathToExistingFile + * @dataProvider recordNewFileDataProvider + */ + public function testRecordNewFile($pathToExistingFile) + { + $content = openssl_random_pseudo_bytes(200); + + $this->filesystemMock + ->expects($this->once()) + ->method('getDirectoryWrite') + ->with(DirectoryList::MEDIA) + ->willReturn($this->directoryMock); + + $this->encodedContextMock + ->expects($this->once()) + ->method('getContent') + ->with() + ->willReturn($content); + + $hashLength = 64; + $fileRelativePathPattern = '#' . preg_quote($this->fileSubdirectoryPath, '#') + . '.{' . $hashLength . '}/' . preg_quote($this->encodedFileName, '#') . '#'; + $this->directoryMock + ->expects($this->once()) + ->method('writeFile') + ->with($this->matchesRegularExpression($fileRelativePathPattern), $content) + ->willReturn($this->directoryMock); + + $this->fileInfoManagerMock + ->expects($this->once()) + ->method('load') + ->with() + ->willReturn($this->fileInfoMock); + + $this->encodedContextMock + ->expects($this->once()) + ->method('getInitializationVector') + ->with() + ->willReturn('init_vector***'); + + /** register file */ + $this->fileInfoFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->callback( + function ($parameters) { + return !empty($parameters['path']) && ('init_vector***' === $parameters['initializationVector']); + } + )) + ->willReturn($this->fileInfoMock); + $this->fileInfoManagerMock + ->expects($this->once()) + ->method('save') + ->with($this->fileInfoMock); + + /** remove old file */ + $this->fileInfoMock + ->expects($this->exactly($pathToExistingFile ? 3 : 1)) + ->method('getPath') + ->with() + ->willReturn($pathToExistingFile); + $directoryName = dirname($pathToExistingFile); + if ($directoryName === '.') { + $this->directoryMock + ->expects($this->once()) + ->method('delete') + ->with($pathToExistingFile); + } elseif ($directoryName) { + $this->directoryMock + ->expects($this->exactly(2)) + ->method('delete') + ->withConsecutive( + [$pathToExistingFile], + [$directoryName] + ); + } + + $this->assertTrue($this->fileRecorder->recordNewFile($this->encodedContextMock)); + } + + /** + * @return array + */ + public function recordNewFileDataProvider() + { + return [ + 'File doesn\'t exist' => [''], + 'Existing file into subdirectory' => ['dir_name/file.txt'], + 'Existing file doesn\'t into subdirectory' => ['file.txt'], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php new file mode 100644 index 0000000000000..31d5c77ce50b0 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php @@ -0,0 +1,228 @@ +integrationServiceMock = $this->getMockBuilder(IntegrationServiceInterface::class) + ->getMock(); + $this->configMock = $this->getMockBuilder(Config::class) + ->disableOriginalConstructor() + ->getMock(); + $this->oauthServiceMock = $this->getMockBuilder(OauthServiceInterface::class) + ->getMock(); + $this->integrationMock = $this->getMockBuilder(Integration::class) + ->disableOriginalConstructor() + ->setMethods([ + 'getId', + 'getConsumerId' + ]) + ->getMock(); + $this->integrationManager = $objectManagerHelper->getObject( + IntegrationManager::class, + [ + 'integrationService' => $this->integrationServiceMock, + 'oauthService' => $this->oauthServiceMock, + 'config' => $this->configMock + ] + ); + } + + /** + * @param string $status + * + * @return array + */ + private function getIntegrationUserData($status) + { + return [ + 'name' => 'ma-integration-user', + 'status' => $status, + 'all_resources' => false, + 'resource' => [ + 'Magento_Analytics::analytics', + 'Magento_Analytics::analytics_api' + ], + ]; + } + + /** + * @return void + */ + public function testActivateIntegrationSuccess() + { + $this->integrationServiceMock->expects($this->once()) + ->method('findByName') + ->with('ma-integration-user') + ->willReturn($this->integrationMock); + $this->integrationMock->expects($this->exactly(2)) + ->method('getId') + ->willReturn(100500); + $integrationData = $this->getIntegrationUserData(Integration::STATUS_ACTIVE); + $integrationData['integration_id'] = 100500; + $this->configMock->expects($this->exactly(2)) + ->method('getConfigDataValue') + ->with('analytics/integration_name', null, null) + ->willReturn('ma-integration-user'); + $this->integrationServiceMock->expects($this->once()) + ->method('update') + ->with($integrationData); + $this->assertTrue($this->integrationManager->activateIntegration()); + } + + /** + * @expectedException \Magento\Framework\Exception\NoSuchEntityException + */ + public function testActivateIntegrationFailureNoSuchEntity() + { + $this->integrationServiceMock->expects($this->once()) + ->method('findByName') + ->with('ma-integration-user') + ->willReturn($this->integrationMock); + $this->integrationMock->expects($this->once()) + ->method('getId') + ->willReturn(null); + $this->configMock->expects($this->once()) + ->method('getConfigDataValue') + ->with('analytics/integration_name', null, null) + ->willReturn('ma-integration-user'); + $this->integrationServiceMock->expects($this->never()) + ->method('update'); + $this->integrationManager->activateIntegration(); + } + + /** + * @dataProvider integrationIdDataProvider + * + * @param int|null $integrationId If null integration is absent. + * @return void + */ + public function testGetTokenNewIntegration($integrationId) + { + $this->configMock->expects($this->atLeastOnce()) + ->method('getConfigDataValue') + ->with('analytics/integration_name', null, null) + ->willReturn('ma-integration-user'); + $this->integrationServiceMock->expects($this->once()) + ->method('findByName') + ->with('ma-integration-user') + ->willReturn($this->integrationMock); + $this->integrationMock->expects($this->once()) + ->method('getConsumerId') + ->willReturn(100500); + $this->integrationMock->expects($this->once()) + ->method('getId') + ->willReturn($integrationId); + if (!$integrationId) { + $this->integrationServiceMock + ->expects($this->once()) + ->method('create') + ->with($this->getIntegrationUserData(Integration::STATUS_INACTIVE)) + ->willReturn($this->integrationMock); + } + $this->oauthServiceMock->expects($this->at(0)) + ->method('getAccessToken') + ->with(100500) + ->willReturn(false); + $this->oauthServiceMock->expects($this->at(2)) + ->method('getAccessToken') + ->with(100500) + ->willReturn('IntegrationToken'); + $this->oauthServiceMock->expects($this->once()) + ->method('createAccessToken') + ->with(100500, true) + ->willReturn(true); + $this->assertEquals('IntegrationToken', $this->integrationManager->generateToken()); + } + + /** + * @dataProvider integrationIdDataProvider + * + * @param int|null $integrationId If null integration is absent. + * @return void + */ + public function testGetTokenExistingIntegration($integrationId) + { + $this->configMock->expects($this->atLeastOnce()) + ->method('getConfigDataValue') + ->with('analytics/integration_name', null, null) + ->willReturn('ma-integration-user'); + $this->integrationServiceMock->expects($this->once()) + ->method('findByName') + ->with('ma-integration-user') + ->willReturn($this->integrationMock); + $this->integrationMock->expects($this->once()) + ->method('getConsumerId') + ->willReturn(100500); + $this->integrationMock->expects($this->once()) + ->method('getId') + ->willReturn($integrationId); + if (!$integrationId) { + $this->integrationServiceMock + ->expects($this->once()) + ->method('create') + ->with($this->getIntegrationUserData(Integration::STATUS_INACTIVE)) + ->willReturn($this->integrationMock); + } + $this->oauthServiceMock->expects($this->once()) + ->method('getAccessToken') + ->with(100500) + ->willReturn('IntegrationToken'); + $this->oauthServiceMock->expects($this->never()) + ->method('createAccessToken'); + $this->assertEquals('IntegrationToken', $this->integrationManager->generateToken()); + } + + /** + * @return array + */ + public function integrationIdDataProvider() + { + return [ + [1], + [null], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php new file mode 100644 index 0000000000000..afda37962a3cb --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php @@ -0,0 +1,166 @@ +linkInterfaceFactoryMock = $this->getMockBuilder(LinkInterfaceFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->fileInfoManagerMock = $this->getMockBuilder(FileInfoManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->storeManagerInterfaceMock = $this->getMockBuilder(StoreManagerInterface::class) + ->getMockForAbstractClass(); + $this->linkInterfaceMock = $this->getMockBuilder(LinkInterface::class) + ->getMockForAbstractClass(); + $this->fileInfoMock = $this->getMockBuilder(FileInfo::class) + ->disableOriginalConstructor() + ->getMock(); + $this->storeMock = $this->getMockBuilder(Store::class) + ->disableOriginalConstructor() + ->getMock(); + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->linkProvider = $this->objectManagerHelper->getObject( + LinkProvider::class, + [ + 'linkFactory' => $this->linkInterfaceFactoryMock, + 'fileInfoManager' => $this->fileInfoManagerMock, + 'storeManager' => $this->storeManagerInterfaceMock + ] + ); + } + + public function testGet() + { + $baseUrl = 'http://magento.local/pub/media/'; + $fileInfoPath = 'analytics/data.tgz'; + $fileInitializationVector = 'er312esq23eqq'; + $this->fileInfoManagerMock->expects($this->once()) + ->method('load') + ->willReturn($this->fileInfoMock); + $this->linkInterfaceFactoryMock->expects($this->once()) + ->method('create') + ->with( + [ + 'initializationVector' => base64_encode($fileInitializationVector), + 'url' => $baseUrl . $fileInfoPath + ] + ) + ->willReturn($this->linkInterfaceMock); + $this->storeManagerInterfaceMock->expects($this->once()) + ->method('getStore')->willReturn($this->storeMock); + $this->storeMock->expects($this->once()) + ->method('getBaseUrl') + ->with( + UrlInterface::URL_TYPE_MEDIA + ) + ->willReturn($baseUrl); + $this->fileInfoMock->expects($this->atLeastOnce()) + ->method('getPath') + ->willReturn($fileInfoPath); + $this->fileInfoMock->expects($this->atLeastOnce()) + ->method('getInitializationVector') + ->willReturn($fileInitializationVector); + $this->assertEquals($this->linkInterfaceMock, $this->linkProvider->get()); + } + + /** + * @param string|null $fileInfoPath + * @param string|null $fileInitializationVector + * + * @dataProvider fileNotReadyDataProvider + * @expectedException \Magento\Framework\Exception\NoSuchEntityException + * @expectedExceptionMessage File is not ready yet. + */ + public function testFileNotReady($fileInfoPath, $fileInitializationVector) + { + $this->fileInfoManagerMock->expects($this->once()) + ->method('load') + ->willReturn($this->fileInfoMock); + $this->fileInfoMock->expects($this->once()) + ->method('getPath') + ->willReturn($fileInfoPath); + $this->fileInfoMock->expects($this->any()) + ->method('getInitializationVector') + ->willReturn($fileInitializationVector); + $this->linkProvider->get(); + } + + /** + * @return array + */ + public function fileNotReadyDataProvider() + { + return [ + [null, 'initVector'], + ['path', null], + ['', 'initVector'], + ['path', ''], + ['', ''], + [null, null] + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php new file mode 100644 index 0000000000000..03fe7d968a7f5 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php @@ -0,0 +1,76 @@ +flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManagerHelper = new ObjectManagerHelper($this); + $this->notificationTime = $objectManagerHelper->getObject( + NotificationTime::class, + [ + 'flagManager' => $this->flagManagerMock, + ] + ); + } + + public function testStoreLastTimeNotification() + { + $value = 100500; + + $this->flagManagerMock + ->expects($this->once()) + ->method('saveFlag') + ->with(NotificationTime::NOTIFICATION_TIME, $value) + ->willReturn(true); + $this->assertTrue($this->notificationTime->storeLastTimeNotification($value)); + } + + public function testGetLastTimeNotification() + { + $value = 100500; + + $this->flagManagerMock + ->expects($this->once()) + ->method('getFlagData') + ->with(NotificationTime::NOTIFICATION_TIME) + ->willReturn(true); + $this->assertEquals($value, $this->notificationTime->getLastTimeNotification()); + } + + public function testUnsetLastTimeNotificationValue() + { + $this->flagManagerMock + ->expects($this->once()) + ->method('deleteFlag') + ->with(NotificationTime::NOTIFICATION_TIME) + ->willReturn(true); + $this->assertTrue($this->notificationTime->unsetLastTimeNotificationValue()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php new file mode 100644 index 0000000000000..38d073a4b4550 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php @@ -0,0 +1,147 @@ +subscriptionUpdateHandlerMock = $this->getMockBuilder(SubscriptionUpdateHandler::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configValueMock = $this->getMockBuilder(Value::class) + ->disableOriginalConstructor() + ->setMethods(['isValueChanged', 'getPath', 'getScope', 'getOldValue']) + ->getMock(); + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->plugin = $this->objectManagerHelper->getObject( + BaseUrlConfigPlugin::class, + [ + 'subscriptionUpdateHandler' => $this->subscriptionUpdateHandlerMock, + ] + ); + } + + /** + * @param array $configValueData + * @return void + * @dataProvider afterSavePluginIsNotApplicableDataProvider + */ + public function testAfterSavePluginIsNotApplicable( + array $configValueData + ) { + $this->configValueMock + ->method('isValueChanged') + ->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, + $this->plugin->afterAfterSave($this->configValueMock, $this->configValueMock) + ); + } + + /** + * @return array + */ + public function afterSavePluginIsNotApplicableDataProvider() + { + return [ + 'Value has not been changed' => [ + 'Config Value Data' => [ + 'isValueChanged' => false, + 'path' => Store::XML_PATH_SECURE_BASE_URL, + 'scope' => ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ], + ], + 'Unsecure URL has been changed' => [ + 'Config Value Data' => [ + 'isValueChanged' => true, + 'path' => Store::XML_PATH_UNSECURE_BASE_URL, + 'scope' => ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ], + ], + 'Secure URL has been changed not in the Default scope' => [ + 'Config Value Data' => [ + 'isValueChanged' => true, + 'path' => Store::XML_PATH_SECURE_BASE_URL, + 'scope' => ScopeInterface::SCOPE_STORES + ], + ], + ]; + } + + /** + * @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 new file mode 100644 index 0000000000000..ee507d88c68db --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php @@ -0,0 +1,153 @@ +configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->otpRequestMock = $this->getMockBuilder(OTPRequest::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->reportUrlProvider = $this->objectManagerHelper->getObject( + ReportUrlProvider::class, + [ + 'config' => $this->configMock, + 'analyticsToken' => $this->analyticsTokenMock, + 'otpRequest' => $this->otpRequestMock, + 'flagManager' => $this->flagManagerMock, + 'urlReportConfigPath' => $this->urlReportConfigPath, + ] + ); + } + + /** + * @param bool $isTokenExist + * @param string|null $otp If null OTP was not received. + * + * @dataProvider getUrlDataProvider + */ + public function testGetUrl($isTokenExist, $otp) + { + $reportUrl = 'https://example.com/report'; + $url = ''; + + $this->configMock + ->expects($this->once()) + ->method('getValue') + ->with($this->urlReportConfigPath) + ->willReturn($reportUrl); + $this->analyticsTokenMock + ->expects($this->once()) + ->method('isTokenExist') + ->with() + ->willReturn($isTokenExist); + $this->otpRequestMock + ->expects($isTokenExist ? $this->once() : $this->never()) + ->method('call') + ->with() + ->willReturn($otp); + if ($isTokenExist && $otp) { + $url = $reportUrl . '?' . http_build_query(['otp' => $otp], '', '&'); + } + $this->assertSame($url ?: $reportUrl, $this->reportUrlProvider->getUrl()); + } + + /** + * @return array + */ + public function getUrlDataProvider() + { + return [ + 'TokenDoesNotExist' => [false, null], + 'TokenExistAndOtpEmpty' => [true, null], + '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/ReportWriterTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php new file mode 100644 index 0000000000000..96ac1143ec5ec --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php @@ -0,0 +1,213 @@ +configInterfaceMock = $this->getMockBuilder(ConfigInterface::class)->getMockForAbstractClass(); + $this->reportValidatorMock = $this->getMockBuilder(ReportValidator::class) + ->disableOriginalConstructor()->getMock(); + $this->providerFactoryMock = $this->getMockBuilder(ProviderFactory::class) + ->disableOriginalConstructor()->getMock(); + $this->reportProviderMock = $this->getMockBuilder(ReportProvider::class) + ->disableOriginalConstructor()->getMock(); + $this->directoryMock = $this->getMockBuilder(WriteInterface::class)->getMockForAbstractClass(); + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->reportWriter = $this->objectManagerHelper->getObject( + ReportWriter::class, + [ + 'config' => $this->configInterfaceMock, + 'reportValidator' => $this->reportValidatorMock, + 'providerFactory' => $this->providerFactoryMock + ] + ); + } + + /** + * @param array $configData + * @return void + * + * @dataProvider configDataProvider + */ + public function testWrite(array $configData) + { + $errors = []; + $fileData = [ + ['number' => 1, 'type' => 'Shoes Usual'] + ]; + $this->configInterfaceMock + ->expects($this->once()) + ->method('get') + ->with() + ->willReturn([$configData]); + $this->providerFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->providerClass) + ->willReturn($this->reportProviderMock); + $parameterName = isset(reset($configData)[0]['parameters']['name']) + ? reset($configData)[0]['parameters']['name'] + : ''; + $this->reportProviderMock->expects($this->once()) + ->method('getReport') + ->with($parameterName ?: null) + ->willReturn($fileData); + $errorStreamMock = $this->getMockBuilder( + \Magento\Framework\Filesystem\File\WriteInterface::class + )->getMockForAbstractClass(); + $errorStreamMock + ->expects($this->once()) + ->method('lock') + ->with(); + $errorStreamMock + ->expects($this->exactly(2)) + ->method('writeCsv') + ->withConsecutive( + [array_keys($fileData[0])], + [$fileData[0]] + ); + $errorStreamMock->expects($this->once())->method('unlock'); + $errorStreamMock->expects($this->once())->method('close'); + if ($parameterName) { + $this->reportValidatorMock + ->expects($this->once()) + ->method('validate') + ->with($parameterName) + ->willReturn($errors); + } + $this->directoryMock + ->expects($this->once()) + ->method('openFile') + ->with( + $this->stringContains('/var/tmp' . $parameterName ?: $this->reportName), + 'w+' + )->willReturn($errorStreamMock); + $this->assertTrue($this->reportWriter->write($this->directoryMock, '/var/tmp')); + } + + /** + * @param array $configData + * @return void + * + * @dataProvider configDataProvider + */ + public function testWriteErrorFile($configData) + { + $errors = ['orders', 'SQL Error: test']; + $this->configInterfaceMock->expects($this->once())->method('get')->willReturn([$configData]); + $errorStreamMock = $this->getMockBuilder( + \Magento\Framework\Filesystem\File\WriteInterface::class + )->getMockForAbstractClass(); + $errorStreamMock->expects($this->once())->method('lock'); + $errorStreamMock->expects($this->once())->method('writeCsv')->with($errors); + $errorStreamMock->expects($this->once())->method('unlock'); + $errorStreamMock->expects($this->once())->method('close'); + $this->reportValidatorMock->expects($this->once())->method('validate')->willReturn($errors); + $this->directoryMock->expects($this->once())->method('openFile')->with('/var/tmp' . 'errors.csv', 'w+') + ->willReturn($errorStreamMock); + $this->assertTrue($this->reportWriter->write($this->directoryMock, '/var/tmp')); + } + + /** + * @return void + */ + public function testWriteEmptyReports() + { + $this->configInterfaceMock->expects($this->once())->method('get')->willReturn([]); + $this->reportValidatorMock->expects($this->never())->method('validate'); + $this->directoryMock->expects($this->never())->method('openFile'); + $this->assertTrue($this->reportWriter->write($this->directoryMock, '/var/tmp')); + } + + /** + * @return array + */ + public function configDataProvider() + { + return [ + 'reportProvider' => [ + [ + 'providers' => [ + [ + 'name' => $this->providerName, + 'class' => $this->providerClass, + 'parameters' => [ + 'name' => $this->reportName + ], + ] + ] + ] + ], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php new file mode 100644 index 0000000000000..654fad74ef309 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php @@ -0,0 +1,50 @@ +moduleManagerMock = $this->getMockBuilder(ModuleManager::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManagerHelper = new ObjectManagerHelper($this); + $this->moduleIterator = $objectManagerHelper->getObject( + ModuleIterator::class, + [ + 'moduleManager' => $this->moduleManagerMock, + 'iterator' => new \ArrayIterator([0 => ['module_name' => 'Coco_Module']]) + ] + ); + } + + public function testCurrent() + { + $this->moduleManagerMock->expects($this->once()) + ->method('isEnabled') + ->with('Coco_Module') + ->willReturn(true); + foreach ($this->moduleIterator as $item) { + $this->assertEquals(['module_name' => 'Coco_Module', 'status' => 'Enabled'], $item); + } + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php new file mode 100644 index 0000000000000..a2f9be1461c15 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php @@ -0,0 +1,123 @@ +scopeConfigMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->websiteMock = $this->getMockBuilder(WebsiteInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->storeMock = $this->getMockBuilder(StoreInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configPaths = [ + 'web/unsecure/base_url', + 'currency/options/base', + 'general/locale/timezone' + ]; + + $this->storeConfigurationProvider = new StoreConfigurationProvider( + $this->scopeConfigMock, + $this->storeManagerMock, + $this->configPaths + ); + } + + public function testGetReport() + { + $map = [ + ['web/unsecure/base_url', 'default', 0, '127.0.0.1'], + ['currency/options/base', 'default', 0, 'USD'], + ['general/locale/timezone', 'default', 0, 'America/Dawson'], + ['web/unsecure/base_url', 'websites', 1, '127.0.0.2'], + ['currency/options/base', 'websites', 1, 'USD'], + ['general/locale/timezone', 'websites', 1, 'America/Belem'], + ['web/unsecure/base_url', 'stores', 2, '127.0.0.3'], + ['currency/options/base', 'stores', 2, 'USD'], + ['general/locale/timezone', 'stores', 2, 'America/Phoenix'], + ]; + + $this->scopeConfigMock + ->method('getValue') + ->will($this->returnValueMap($map)); + + $this->storeManagerMock->expects($this->once()) + ->method('getWebsites') + ->willReturn([$this->websiteMock]); + + $this->storeManagerMock->expects($this->once()) + ->method('getStores') + ->willReturn([$this->storeMock]); + + $this->websiteMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + + $this->storeMock->expects($this->once()) + ->method('getId') + ->willReturn(2); + $result = iterator_to_array($this->storeConfigurationProvider->getReport()); + $resultValues = []; + foreach ($result as $item) { + $resultValues[] = array_values($item); + } + array_multisort($resultValues); + array_multisort($map); + $this->assertEquals($resultValues, $map); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php new file mode 100644 index 0000000000000..2e52a13f90bbf --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php @@ -0,0 +1,196 @@ +scopeConfigMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->getMockForAbstractClass(); + + $this->analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->statusProvider = $this->objectManagerHelper->getObject( + SubscriptionStatusProvider::class, + [ + 'scopeConfig' => $this->scopeConfigMock, + 'analyticsToken' => $this->analyticsTokenMock, + 'flagManager' => $this->flagManagerMock, + ] + ); + } + + /** + * @param array $flagManagerData + * @dataProvider getStatusShouldBeFailedDataProvider + */ + public function testGetStatusShouldBeFailed(array $flagManagerData) + { + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(false); + $this->scopeConfigMock->expects($this->once()) + ->method('getValue') + ->with('analytics/subscription/enabled') + ->willReturn(true); + + $this->expectFlagManagerReturn($flagManagerData); + $this->assertEquals(SubscriptionStatusProvider::FAILED, $this->statusProvider->getStatus()); + } + + /** + * @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($isTokenExist); + $this->scopeConfigMock->expects($this->once()) + ->method('getValue') + ->with('analytics/subscription/enabled') + ->willReturn(true); + + $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); + $this->scopeConfigMock->expects($this->once()) + ->method('getValue') + ->with('analytics/subscription/enabled') + ->willReturn(true); + $this->assertEquals(SubscriptionStatusProvider::ENABLED, $this->statusProvider->getStatus()); + } + + public function testGetStatusShouldBeDisabled() + { + $this->scopeConfigMock->expects($this->once()) + ->method('getValue') + ->with('analytics/subscription/enabled') + ->willReturn(false); + $this->assertEquals(SubscriptionStatusProvider::DISABLED, $this->statusProvider->getStatus()); + } + + /** + * @param array $mapping + */ + private function expectFlagManagerReturn(array $mapping) + { + $this->flagManagerMock + ->method('getFlagData') + ->willReturnMap($mapping); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php b/app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php new file mode 100644 index 0000000000000..536a7dbb5dfe9 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php @@ -0,0 +1,106 @@ +subscriptionStatusMock = $this->getMockBuilder(SubscriptionStatusProvider::class) + ->disableOriginalConstructor() + ->getMock(); + $this->urlBuilderMock = $this->getMockBuilder(UrlInterface::class) + ->getMockForAbstractClass(); + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->notification = $this->objectManagerHelper->getObject( + NotificationAboutFailedSubscription::class, + [ + 'subscriptionStatusProvider' => $this->subscriptionStatusMock, + 'urlBuilder' => $this->urlBuilderMock + ] + ); + } + + public function testIsDisplayedWhenMessageShouldBeDisplayed() + { + $this->subscriptionStatusMock->expects($this->once()) + ->method('getStatus') + ->willReturn( + SubscriptionStatusProvider::FAILED + ); + $this->assertTrue($this->notification->isDisplayed()); + } + + /** + * @dataProvider notDisplayedNotificationStatuses + * + * @param $status + */ + public function testIsDisplayedWhenMessageShouldNotBeDisplayed($status) + { + $this->subscriptionStatusMock->expects($this->once()) + ->method('getStatus') + ->willReturn($status); + $this->assertFalse($this->notification->isDisplayed()); + } + + public function testGetTextShouldBuildMessage() + { + $retryUrl = 'http://magento.dev/retryUrl'; + $this->urlBuilderMock->expects($this->once()) + ->method('getUrl') + ->with('analytics/subscription/retry') + ->willReturn($retryUrl); + $messageDetails = 'Failed to synchronize data to the Magento Business Intelligence service. '; + $messageDetails .= sprintf('Retry Synchronization', $retryUrl); + $this->assertEquals($messageDetails, $this->notification->getText()); + } + + /** + * Provide statuses according to which message should not be displayed. + * + * @return array + */ + public function notDisplayedNotificationStatuses() + { + return [ + [SubscriptionStatusProvider::PENDING], + [SubscriptionStatusProvider::DISABLED], + [SubscriptionStatusProvider::ENABLED], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php new file mode 100644 index 0000000000000..325d3d4a85c7e --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php @@ -0,0 +1,121 @@ +objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\ReportXml\Config\Converter\Xml::class + ); + } + + /** + * @return void + */ + public function testConvertNoElements() + { + $this->assertEmpty( + $this->subject->convert(new \DOMDocument()) + ); + } + + /** + * @return void + */ + public function testConvert() + { + $dom = new \DOMDocument(); + + $expectedArray = [ + 'config' => [ + [ + 'noNamespaceSchemaLocation' => 'urn:magento:module:Magento_Analytics:etc/reports.xsd', + 'report' => [ + [ + 'name' => 'test_report_1', + 'connection' => 'sales', + 'source' => [ + [ + 'name' => 'sales_order', + 'alias' => 'orders', + 'attribute' => [ + [ + 'name' => 'entity_id', + 'alias' => 'identifier', + ] + ], + 'filter' => [ + [ + 'glue' => 'and', + 'condition' => [ + [ + 'attribute' => 'entity_id', + 'operator' => 'gt', + '_value' => '10' + ] + ] + ] + ] + ] + ] + ], + [ + 'name' => 'test_report_2', + 'connection' => 'default', + 'source' => [ + [ + 'name' => 'customer_entity', + 'alias' => 'customers', + 'attribute' => [ + [ + 'name' => 'email' + ] + ], + 'filter' => [ + [ + 'glue' => 'and', + 'condition' => [ + [ + 'attribute' => 'dob', + 'operator' => 'null' + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ]; + + $dom->loadXML(file_get_contents(__DIR__ . '/../_files/valid_reports.xml')); + + $this->assertEquals($expectedArray, $this->subject->convert($dom)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php new file mode 100644 index 0000000000000..f69b40118b935 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php @@ -0,0 +1,47 @@ +mapper = new Mapper(); + } + + public function testExecute() + { + $configData['config'][0]['report'] = [ + [ + 'source' => ['product'], + 'name' => 'Product', + ] + ]; + $expectedResult = [ + 'Product' => [ + 'source' => 'product', + 'name' => 'Product', + ] + ]; + $this->assertEquals($this->mapper->execute($configData), $expectedResult); + } + + public function testExecuteWithoutReports() + { + $configData = []; + $this->assertEquals($this->mapper->execute($configData), []); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/_files/valid_reports.xml b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/_files/valid_reports.xml new file mode 100644 index 0000000000000..e04ee96163797 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/_files/valid_reports.xml @@ -0,0 +1,25 @@ + + + + + + + + 10 + + + + + + + + + + + + diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php new file mode 100644 index 0000000000000..1b89a0d3ad671 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php @@ -0,0 +1,64 @@ +dataMock = $this->getMockBuilder(DataInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->config = $this->objectManagerHelper->getObject( + Config::class, + [ + 'data' => $this->dataMock, + ] + ); + } + + public function testGet() + { + $queryName = 'query string'; + $queryResult = [ 'query' => 1 ]; + + $this->dataMock + ->expects($this->once()) + ->method('get') + ->with($queryName) + ->willReturn($queryResult); + + $this->assertSame($queryResult, $this->config->get($queryName)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php new file mode 100644 index 0000000000000..330f7f1a6707a --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php @@ -0,0 +1,106 @@ +resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionMock = $this->getMockBuilder(MysqlPdoAdapter::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionNewMock = $this->getMockBuilder(MysqlPdoAdapter::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->connectionFactory = $this->objectManagerHelper->getObject( + ConnectionFactory::class, + [ + 'resourceConnection' => $this->resourceConnectionMock, + 'objectManager' => $this->objectManagerMock, + ] + ); + } + + public function testGetConnection() + { + $connectionName = 'read'; + + $this->resourceConnectionMock + ->expects($this->once()) + ->method('getConnection') + ->with($connectionName) + ->willReturn($this->connectionMock); + + $this->connectionMock + ->expects($this->once()) + ->method('getConfig') + ->with() + ->willReturn(['persistent' => 1]); + + $this->objectManagerMock + ->expects($this->once()) + ->method('create') + ->with(get_class($this->connectionMock), ['config' => ['use_buffered_query' => false]]) + ->willReturn($this->connectionNewMock); + + $this->assertSame($this->connectionNewMock, $this->connectionFactory->getConnection($connectionName)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php new file mode 100644 index 0000000000000..6ebfd1ffa2da6 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php @@ -0,0 +1,143 @@ +nameResolverMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\NameResolver::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectBuilderMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\SelectBuilder::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->selectBuilderMock->expects($this->any()) + ->method('getFilters') + ->willReturn([]); + + $this->conditionResolverMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\ConditionResolver::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\ReportXml\DB\Assembler\FilterAssembler::class, + [ + 'conditionResolver' => $this->conditionResolverMock, + 'nameResolver' => $this->nameResolverMock + ] + ); + } + + /** + * @return void + */ + public function testAssembleEmpty() + { + $queryConfigMock = [ + 'source' => [ + 'name' => 'sales_order', + 'alias' => 'sales' + ] + ]; + + $this->selectBuilderMock->expects($this->never()) + ->method('setFilters'); + + $this->assertEquals( + $this->selectBuilderMock, + $this->subject->assemble($this->selectBuilderMock, $queryConfigMock) + ); + } + + /** + * @return void + */ + public function testAssembleNotEmpty() + { + $queryConfigMock = [ + 'source' => [ + 'name' => 'sales_order', + 'alias' => 'sales', + 'filter' => [ + [ + 'glue' => 'and', + 'condition' => [ + [ + 'attribute' => 'entity_id', + 'operator' => 'null' + ] + ] + ] + ] + ] + ]; + + $this->nameResolverMock->expects($this->any()) + ->method('getAlias') + ->with($queryConfigMock['source']) + ->willReturn($queryConfigMock['source']['alias']); + + $this->conditionResolverMock->expects($this->once()) + ->method('getFilter') + ->with( + $this->selectBuilderMock, + $queryConfigMock['source']['filter'], + $queryConfigMock['source']['alias'] + ) + ->willReturn('(sales.entity_id IS NULL)'); + + $this->selectBuilderMock->expects($this->once()) + ->method('setFilters') + ->with(['(sales.entity_id IS NULL)']); + + $this->assertEquals( + $this->selectBuilderMock, + $this->subject->assemble($this->selectBuilderMock, $queryConfigMock) + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php new file mode 100644 index 0000000000000..cbabac5613a8b --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php @@ -0,0 +1,167 @@ +nameResolverMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\NameResolver::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectBuilderMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\SelectBuilder::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->selectBuilderMock->expects($this->any()) + ->method('getColumns') + ->willReturn([]); + + $this->columnsResolverMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\ColumnsResolver::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->resourceConnection = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\ReportXml\DB\Assembler\FromAssembler::class, + [ + 'nameResolver' => $this->nameResolverMock, + 'columnsResolver' => $this->columnsResolverMock, + 'resourceConnection' => $this->resourceConnection, + ] + ); + } + + /** + * @dataProvider assembleDataProvider + * @param array $queryConfig + * @param string $tableName + * @return void + */ + public function testAssemble(array $queryConfig, $tableName) + { + $this->nameResolverMock->expects($this->any()) + ->method('getAlias') + ->with($queryConfig['source']) + ->willReturn($queryConfig['source']['alias']); + + $this->nameResolverMock->expects($this->once()) + ->method('getName') + ->with($queryConfig['source']) + ->willReturn($queryConfig['source']['name']); + + $this->resourceConnection + ->expects($this->once()) + ->method('getTableName') + ->with($queryConfig['source']['name']) + ->willReturn($tableName); + + $this->selectBuilderMock->expects($this->once()) + ->method('setFrom') + ->with([$queryConfig['source']['alias'] => $tableName]); + + $this->columnsResolverMock->expects($this->once()) + ->method('getColumns') + ->with($this->selectBuilderMock, $queryConfig['source']) + ->willReturn(['entity_id' => 'sales.entity_id']); + + $this->selectBuilderMock->expects($this->once()) + ->method('setColumns') + ->with(['entity_id' => 'sales.entity_id']); + + $this->assertEquals( + $this->selectBuilderMock, + $this->subject->assemble($this->selectBuilderMock, $queryConfig) + ); + } + + /** + * @return array + */ + public function assembleDataProvider() + { + return [ + 'Tables without prefixes' => [ + [ + 'source' => [ + 'name' => 'sales_order', + 'alias' => 'sales', + 'attribute' => [ + [ + 'name' => 'entity_id' + ] + ], + ], + ], + 'sales_order', + ], + 'Tables with prefixes' => [ + [ + 'source' => [ + 'name' => 'sales_order', + 'alias' => 'sales', + 'attribute' => [ + [ + 'name' => 'entity_id' + ] + ], + ], + ], + 'pref_sales_order', + ] + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php new file mode 100644 index 0000000000000..b913689513ce5 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php @@ -0,0 +1,279 @@ +nameResolverMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\NameResolver::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectBuilderMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\SelectBuilder::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->selectBuilderMock->expects($this->any()) + ->method('getFilters') + ->willReturn([]); + $this->selectBuilderMock->expects($this->any()) + ->method('getColumns') + ->willReturn([]); + $this->selectBuilderMock->expects($this->any()) + ->method('getJoins') + ->willReturn([]); + + $this->columnsResolverMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\ColumnsResolver::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->conditionResolverMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\ConditionResolver::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->resourceConnection = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\ReportXml\DB\Assembler\JoinAssembler::class, + [ + 'conditionResolver' => $this->conditionResolverMock, + 'nameResolver' => $this->nameResolverMock, + 'columnsResolver' => $this->columnsResolverMock, + 'resourceConnection' => $this->resourceConnection, + ] + ); + } + + /** + * @return void + */ + public function testAssembleEmpty() + { + $queryConfigMock = [ + 'source' => [ + 'name' => 'sales_order', + 'alias' => 'sales' + ] + ]; + + $this->selectBuilderMock->expects($this->never()) + ->method('setColumns'); + $this->selectBuilderMock->expects($this->never()) + ->method('setFilters'); + $this->selectBuilderMock->expects($this->never()) + ->method('setJoins'); + + $this->assertEquals( + $this->selectBuilderMock, + $this->subject->assemble($this->selectBuilderMock, $queryConfigMock) + ); + } + + /** + * @param array $queryConfigMock + * @param array $joinsMock + * @param array $tablesMapping + * @return void + * @dataProvider assembleNotEmptyDataProvider + */ + public function testAssembleNotEmpty(array $queryConfigMock, array $joinsMock, array $tablesMapping) + { + $filtersMock = []; + + $this->nameResolverMock->expects($this->at(0)) + ->method('getAlias') + ->with($queryConfigMock['source']) + ->willReturn($queryConfigMock['source']['alias']); + $this->nameResolverMock->expects($this->at(1)) + ->method('getAlias') + ->with($queryConfigMock['source']['link-source'][0]) + ->willReturn($queryConfigMock['source']['link-source'][0]['alias']); + $this->nameResolverMock->expects($this->once()) + ->method('getName') + ->with($queryConfigMock['source']['link-source'][0]) + ->willReturn($queryConfigMock['source']['link-source'][0]['name']); + + $this->resourceConnection + ->expects($this->any()) + ->method('getTableName') + ->willReturnOnConsecutiveCalls(...array_values($tablesMapping)); + + $this->conditionResolverMock->expects($this->at(0)) + ->method('getFilter') + ->with( + $this->selectBuilderMock, + $queryConfigMock['source']['link-source'][0]['using'], + $queryConfigMock['source']['link-source'][0]['alias'], + $queryConfigMock['source']['alias'] + ) + ->willReturn('(billing.parent_id = `sales`.`entity_id`)'); + + if (isset($queryConfigMock['source']['link-source'][0]['filter'])) { + $filtersMock = ['(sales.entity_id IS NULL)']; + + $this->conditionResolverMock->expects($this->at(1)) + ->method('getFilter') + ->with( + $this->selectBuilderMock, + $queryConfigMock['source']['link-source'][0]['filter'], + $queryConfigMock['source']['link-source'][0]['alias'], + $queryConfigMock['source']['alias'] + ) + ->willReturn($filtersMock[0]); + + $this->columnsResolverMock->expects($this->once()) + ->method('getColumns') + ->with($this->selectBuilderMock, $queryConfigMock['source']['link-source'][0]) + ->willReturn( + [ + 'entity_id' => 'sales.entity_id', + 'billing_address_id' => 'billing.entity_id' + ] + ); + + $this->selectBuilderMock->expects($this->once()) + ->method('setColumns') + ->with( + [ + 'entity_id' => 'sales.entity_id', + 'billing_address_id' => 'billing.entity_id' + ] + ); + } + + $this->selectBuilderMock->expects($this->once()) + ->method('setFilters') + ->with($filtersMock); + $this->selectBuilderMock->expects($this->once()) + ->method('setJoins') + ->with($joinsMock); + + $this->assertEquals( + $this->selectBuilderMock, + $this->subject->assemble($this->selectBuilderMock, $queryConfigMock) + ); + } + + /** + * @return array + */ + public function assembleNotEmptyDataProvider() + { + return [ + [ + [ + 'source' => [ + 'name' => 'sales_order', + 'alias' => 'sales', + 'link-source' => [ + [ + 'name' => 'sales_order_address', + 'alias' => 'billing', + 'link-type' => 'left', + 'attribute' => [ + [ + 'alias' => 'billing_address_id', + 'name' => 'entity_id' + ] + ], + 'using' => [ + [ + 'glue' => 'and', + 'condition' => [ + [ + 'attribute' => 'parent_id', + 'operator' => 'eq', + 'type' => 'identifier', + '_value' => 'entity_id' + ] + ] + ] + ], + 'filter' => [ + [ + 'glue' => 'and', + 'condition' => [ + [ + 'attribute' => 'entity_id', + 'operator' => 'null' + ] + ] + ] + ] + ] + ] + ] + ], + [ + 'billing' => [ + 'link-type' => 'left', + 'table' => [ + 'billing' => 'pref_sales_order_address' + ], + 'condition' => '(billing.parent_id = `sales`.`entity_id`)' + ] + ], + ['sales_order_address' => 'pref_sales_order_address'] + ] + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php new file mode 100644 index 0000000000000..c8ab79625e9c3 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php @@ -0,0 +1,150 @@ +selectBuilderMock = $this->getMockBuilder(SelectBuilder::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionMock = $this->getMockBuilder(AdapterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManager = new ObjectManagerHelper($this); + $this->columnsResolver = $objectManager->getObject( + ColumnsResolver::class, + [ + 'nameResolver' => new NameResolver(), + 'resourceConnection' => $this->resourceConnectionMock + ] + ); + } + + public function testGetColumnsWithoutAttributes() + { + $this->assertEquals($this->columnsResolver->getColumns($this->selectBuilderMock, []), []); + } + + /** + * @dataProvider getColumnsDataProvider + */ + public function testGetColumnsWithFunction($expectedColumns, $expectedGroup, $entityConfig) + { + $this->resourceConnectionMock->expects($this->any()) + ->method('getConnection') + ->willReturn($this->connectionMock); + $this->connectionMock->expects($this->any()) + ->method('quoteIdentifier') + ->with('cpe.name') + ->willReturn('`cpe`.`name`'); + $this->selectBuilderMock->expects($this->once()) + ->method('getColumns') + ->willReturn([]); + $this->selectBuilderMock->expects($this->once()) + ->method('getGroup') + ->willReturn([]); + $this->selectBuilderMock->expects($this->once()) + ->method('setGroup') + ->with($expectedGroup); + $this->assertEquals( + $expectedColumns, + $this->columnsResolver->getColumns( + $this->selectBuilderMock, + $entityConfig + ) + ); + } + + /** + * @return array + */ + public function getColumnsDataProvider() + { + return [ + 'COUNT( DISTINCT `cpe`.`name`) AS name' => [ + 'expectedColumns' => [ + 'name' => new ColumnValueExpression('COUNT( DISTINCT `cpe`.`name`)') + ], + 'expectedGroup' => [ + 'name' => new ColumnValueExpression('COUNT( DISTINCT `cpe`.`name`)') + ], + 'entityConfig' => + [ + 'name' => 'catalog_product_entity', + 'alias' => 'cpe', + 'attribute' => [ + [ + 'name' => 'name', + 'function' => 'COUNT', + 'distinct' => true, + 'group' => true + ] + ], + ], + ], + 'AVG(`cpe`.`name`) AS avg_name' => [ + 'expectedColumns' => [ + 'avg_name' => new ColumnValueExpression('AVG(`cpe`.`name`)') + ], + 'expectedGroup' => [], + 'entityConfig' => + [ + 'name' => 'catalog_product_entity', + 'alias' => 'cpe', + 'attribute' => [ + [ + 'name' => 'name', + 'alias' => 'avg_name', + 'function' => 'AVG', + ] + ], + ], + ] + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php new file mode 100644 index 0000000000000..2a97e109543cf --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php @@ -0,0 +1,108 @@ +resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectBuilderMock = $this->getMockBuilder(SelectBuilder::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionMock = $this->getMockBuilder(AdapterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->conditionResolver = new ConditionResolver($this->resourceConnectionMock); + } + + public function testGetFilter() + { + $condition = ["type" => "variable", "_value" => "1", "attribute" => "id", "operator" => "neq"]; + $valueCondition = ["type" => "value", "_value" => "2", "attribute" => "first_name", "operator" => "eq"]; + $identifierCondition = [ + "type" => "identifier", + "_value" => "other_field", + "attribute" => "last_name", + "operator" => "eq"]; + $filter = [["glue" => "AND", "condition" => [$valueCondition]]]; + $filterConfig = [ + ["glue" => "OR", "condition" => [$condition], 'filter' => $filter], + ["glue" => "OR", "condition" => [$identifierCondition]], + ]; + $aliasName = 'n'; + $this->selectBuilderMock->expects($this->any()) + ->method('setParams') + ->with(array_merge([], [$condition['_value']])); + + $this->selectBuilderMock->expects($this->once()) + ->method('getParams') + ->willReturn([]); + + $this->selectBuilderMock->expects($this->any()) + ->method('getColumns') + ->willReturn(['price' => new Expression("(n.price = 400)")]); + + $this->resourceConnectionMock->expects($this->once()) + ->method('getConnection') + ->willReturn($this->connectionMock); + + $this->connectionMock->expects($this->any()) + ->method('quote') + ->willReturn("'John'"); + $this->connectionMock->expects($this->exactly(4)) + ->method('quoteIdentifier') + ->willReturnMap([ + ['n.id', false, '`n`.`id`'], + ['n.first_name', false, '`n`.`first_name`'], + ['n.last_name', false, '`n`.`last_name`'], + ['other_field', false, '`other_field`'], + ]); + + $result = "(`n`.`id` != 1 OR ((`n`.`first_name` = 'John'))) OR (`n`.`last_name` = `other_field`)"; + $this->assertEquals( + $result, + $this->conditionResolver->getFilter($this->selectBuilderMock, $filterConfig, $aliasName) + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php new file mode 100644 index 0000000000000..ef051feda0722 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php @@ -0,0 +1,90 @@ +nameResolverMock = $this->getMockBuilder(NameResolver::class) + ->disableOriginalConstructor() + ->setMethods(['getName']) + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->nameResolver = $this->objectManagerHelper->getObject(NameResolver::class); + } + + public function testGetName() + { + $elementConfigMock = [ + 'name' => 'sales_order', + 'alias' => 'sales', + ]; + + $this->assertSame('sales_order', $this->nameResolver->getName($elementConfigMock)); + } + + /** + * @param array $elementConfig + * @param string|null $elementAlias + * + * @dataProvider getAliasDataProvider + */ + public function testGetAlias($elementConfig, $elementAlias) + { + $elementName = 'elementName'; + + $this->nameResolverMock + ->expects($this->once()) + ->method('getName') + ->with($elementConfig) + ->willReturn($elementName); + + $this->assertSame($elementAlias ?: $elementName, $this->nameResolverMock->getAlias($elementConfig)); + } + + /** + * @return array + */ + public function getAliasDataProvider() + { + return [ + 'ElementConfigWithAliases' => [ + ['alias' => 'sales', 'name' => 'sales_order'], + 'sales', + ], + 'ElementConfigWithoutAliases' => [ + ['name' => 'sales_order'], + null, + ] + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php new file mode 100644 index 0000000000000..fad0a80856b70 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php @@ -0,0 +1,125 @@ +connectionFactoryMock = $this->getMockBuilder(ConnectionFactory::class) + ->disableOriginalConstructor()->getMock(); + $this->queryFactoryMock = $this->getMockBuilder(QueryFactory::class) + ->disableOriginalConstructor()->getMock(); + $this->queryMock = $this->getMockBuilder(Query::class)->disableOriginalConstructor() + ->getMock(); + $this->connectionMock = $this->getMockBuilder(AdapterInterface::class)->getMockForAbstractClass(); + $this->selectMock = $this->getMockBuilder(Select::class)->disableOriginalConstructor() + ->getMock(); + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->reportValidator = $this->objectManagerHelper->getObject( + ReportValidator::class, + [ + 'connectionFactory' => $this->connectionFactoryMock, + 'queryFactory' => $this->queryFactoryMock + ] + ); + } + + /** + * @dataProvider errorDataProvider + * @param string $reportName + * @param array $result + * @param \PHPUnit_Framework_MockObject_Stub $queryReturnStub + */ + public function testValidate($reportName, $result, \PHPUnit_Framework_MockObject_Stub $queryReturnStub) + { + $connectionName = 'testConnection'; + $this->queryFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->queryMock); + $this->queryMock->expects($this->once())->method('getConnectionName')->willReturn($connectionName); + $this->connectionFactoryMock->expects($this->once())->method('getConnection') + ->with($connectionName) + ->willReturn($this->connectionMock); + $this->queryMock->expects($this->atLeastOnce())->method('getSelect')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('limit')->with(0); + $this->connectionMock->expects($this->once())->method('query')->with($this->selectMock)->will($queryReturnStub); + $this->assertEquals($result, $this->reportValidator->validate($reportName)); + } + + /** + * Provide variations of the error returning + * + * @return array + */ + public function errorDataProvider() + { + $reportName = 'test'; + $errorMessage = 'SQL Error 42'; + return [ + [ + $reportName, + 'expectedResult' => [], + 'queryReturnStub' => $this->returnValue(null) + ], + [ + $reportName, + 'expectedResult' => [$reportName, $errorMessage], + 'queryReturnStub' => $this->throwException(new \Zend_Db_Statement_Exception($errorMessage)) + ] + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php new file mode 100644 index 0000000000000..fb8f5b4a1ff0e --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php @@ -0,0 +1,103 @@ +resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionMock = $this->getMockBuilder(AdapterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectMock = $this->getMockBuilder(Select::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectBuilder = new SelectBuilder($this->resourceConnectionMock); + } + + public function testCreate() + { + $connectionName = 'MySql'; + $from = ['customer c']; + $columns = ['id', 'name', 'price']; + $filter = 'filter'; + $joins = [ + ['link-type' => 'left', 'table' => 'customer', 'condition' => 'in'], + ['link-type' => 'inner', 'table' => 'price', 'condition' => 'eq'], + ['link-type' => 'right', 'table' => 'attribute', 'condition' => 'neq'], + ]; + $groups = ['id', 'name']; + $this->selectBuilder->setConnectionName($connectionName); + $this->selectBuilder->setFrom($from); + $this->selectBuilder->setColumns($columns); + $this->selectBuilder->setFilters([$filter]); + $this->selectBuilder->setJoins($joins); + $this->selectBuilder->setGroup($groups); + $this->resourceConnectionMock->expects($this->once()) + ->method('getConnection') + ->with($connectionName) + ->willReturn($this->connectionMock); + $this->connectionMock->expects($this->once()) + ->method('select') + ->willReturn($this->selectMock); + $this->selectMock->expects($this->once()) + ->method('from') + ->with($from, []); + $this->selectMock->expects($this->once()) + ->method('columns') + ->with($columns); + $this->selectMock->expects($this->once()) + ->method('where') + ->with($filter); + $this->selectMock->expects($this->once()) + ->method('joinLeft') + ->with($joins[0]['table'], $joins[0]['condition'], []); + $this->selectMock->expects($this->once()) + ->method('joinInner') + ->with($joins[1]['table'], $joins[1]['condition'], []); + $this->selectMock->expects($this->once()) + ->method('joinRight') + ->with($joins[2]['table'], $joins[2]['condition'], []); + $this->selectBuilder->create(); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php new file mode 100644 index 0000000000000..38abc3683f81f --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php @@ -0,0 +1,59 @@ +objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->iteratorIteratorMock = $this->getMockBuilder(\IteratorIterator::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->iteratorFactory = new IteratorFactory( + $this->objectManagerMock + ); + } + + public function testCreate() + { + $arrayObject = new \ArrayIterator([1, 2, 3, 4, 5]); + $this->objectManagerMock->expects($this->once()) + ->method('create') + ->with(\IteratorIterator::class, ['iterator' => $arrayObject]) + ->willReturn($this->iteratorIteratorMock); + + $this->assertEquals($this->iteratorFactory->create($arrayObject), $this->iteratorIteratorMock); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php new file mode 100644 index 0000000000000..e358bf00fe37a --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php @@ -0,0 +1,239 @@ +queryMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\Query::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->configMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\Config::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectMock = $this->getMockBuilder( + \Magento\Framework\DB\Select::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->assemblerMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\Assembler\AssemblerInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->queryCacheMock = $this->getMockBuilder( + \Magento\Framework\App\CacheInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerMock = $this->getMockBuilder( + \Magento\Framework\ObjectManagerInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectHydratorMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\SelectHydrator::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectBuilderFactoryMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\SelectBuilderFactory::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\ReportXml\QueryFactory::class, + [ + 'config' => $this->configMock, + 'selectBuilderFactory' => $this->selectBuilderFactoryMock, + 'assemblers' => [$this->assemblerMock], + 'queryCache' => $this->queryCacheMock, + 'objectManager' => $this->objectManagerMock, + 'selectHydrator' => $this->selectHydratorMock + ] + ); + } + + /** + * @return void + */ + public function testCreateCached() + { + $queryName = 'test_query'; + + $this->queryCacheMock->expects($this->any()) + ->method('load') + ->with($queryName) + ->willReturn('{"connectionName":"sales","config":{},"select_parts":{}}'); + + $this->selectHydratorMock->expects($this->any()) + ->method('recreate') + ->with([]) + ->willReturn($this->selectMock); + + $this->objectManagerMock->expects($this->once()) + ->method('create') + ->with( + \Magento\Analytics\ReportXml\Query::class, + [ + 'select' => $this->selectMock, + 'selectHydrator' => $this->selectHydratorMock, + 'connectionName' => 'sales', + 'config' => [] + ] + ) + ->willReturn($this->queryMock); + + $this->queryCacheMock->expects($this->never()) + ->method('save'); + + $this->assertEquals( + $this->queryMock, + $this->subject->create($queryName) + ); + } + + /** + * @return void + */ + public function testCreateNotCached() + { + $queryName = 'test_query'; + + $queryConfigMock = [ + 'name' => 'test_query', + 'connection' => 'sales' + ]; + + $selectBuilderMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\SelectBuilder::class + ) + ->disableOriginalConstructor() + ->getMock(); + $selectBuilderMock->expects($this->once()) + ->method('setConnectionName') + ->with($queryConfigMock['connection']); + $selectBuilderMock->expects($this->any()) + ->method('create') + ->willReturn($this->selectMock); + $selectBuilderMock->expects($this->any()) + ->method('getConnectionName') + ->willReturn($queryConfigMock['connection']); + + $this->queryCacheMock->expects($this->any()) + ->method('load') + ->with($queryName) + ->willReturn(null); + + $this->configMock->expects($this->any()) + ->method('get') + ->with($queryName) + ->willReturn($queryConfigMock); + + $this->selectBuilderFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($selectBuilderMock); + + $this->assemblerMock->expects($this->once()) + ->method('assemble') + ->with($selectBuilderMock, $queryConfigMock) + ->willReturn($selectBuilderMock); + + $this->objectManagerMock->expects($this->once()) + ->method('create') + ->with( + \Magento\Analytics\ReportXml\Query::class, + [ + 'select' => $this->selectMock, + 'selectHydrator' => $this->selectHydratorMock, + 'connectionName' => $queryConfigMock['connection'], + 'config' => $queryConfigMock + ] + ) + ->willReturn($this->queryMock); + + $this->queryCacheMock->expects($this->once()) + ->method('save') + ->with(json_encode($this->queryMock), $queryName); + + $this->assertEquals( + $this->queryMock, + $this->subject->create($queryName) + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php new file mode 100644 index 0000000000000..e288c668a54f7 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php @@ -0,0 +1,90 @@ +selectMock = $this->getMockBuilder(Select::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectHydratorMock = $this->getMockBuilder(selectHydrator::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->query = $this->objectManagerHelper->getObject( + Query::class, + [ + 'select' => $this->selectMock, + 'connectionName' => $this->connectionName, + 'selectHydrator' => $this->selectHydratorMock, + 'config' => [] + ] + ); + } + + /** + * @return void + */ + public function testJsonSerialize() + { + $selectParts = ['part' => 1]; + + $this->selectHydratorMock + ->expects($this->once()) + ->method('extract') + ->with($this->selectMock) + ->willReturn($selectParts); + + $expectedResult = [ + 'connectionName' => $this->connectionName, + 'select_parts' => $selectParts, + 'config' => [] + ]; + + $this->assertSame($expectedResult, $this->query->jsonSerialize()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php new file mode 100644 index 0000000000000..124d5f32078c8 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php @@ -0,0 +1,180 @@ +selectMock = $this->getMockBuilder( + \Magento\Framework\DB\Select::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->queryMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\Query::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->queryMock->expects($this->any()) + ->method('getSelect') + ->willReturn($this->selectMock); + + $this->iteratorMock = $this->getMockBuilder( + \IteratorIterator::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->statementMock = $this->getMockBuilder( + \Magento\Framework\DB\Statement\Pdo\Mysql::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->statementMock->expects($this->any()) + ->method('getIterator') + ->willReturn($this->iteratorMock); + + $this->connectionMock = $this->getMockBuilder( + \Magento\Framework\DB\Adapter\AdapterInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->queryFactoryMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\QueryFactory::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->iteratorFactoryMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\IteratorFactory::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->iteratorMock = $this->getMockBuilder( + \IteratorIterator::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->connectionFactoryMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\ConnectionFactory::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\ReportXml\ReportProvider::class, + [ + 'queryFactory' => $this->queryFactoryMock, + 'connectionFactory' => $this->connectionFactoryMock, + 'iteratorFactory' => $this->iteratorFactoryMock + ] + ); + } + + /** + * @return void + */ + public function testGetReport() + { + $reportName = 'test_report'; + $connectionName = 'sales'; + + $this->queryFactoryMock->expects($this->once()) + ->method('create') + ->with($reportName) + ->willReturn($this->queryMock); + + $this->connectionFactoryMock->expects($this->once()) + ->method('getConnection') + ->with($connectionName) + ->willReturn($this->connectionMock); + + $this->queryMock->expects($this->once()) + ->method('getConnectionName') + ->willReturn($connectionName); + + $this->queryMock->expects($this->once()) + ->method('getConfig') + ->willReturn( + [ + 'connection' => $connectionName + ] + ); + + $this->connectionMock->expects($this->once()) + ->method('query') + ->with($this->selectMock) + ->willReturn($this->statementMock); + + $this->iteratorFactoryMock->expects($this->once()) + ->method('create') + ->with($this->statementMock, null) + ->willReturn($this->iteratorMock); + $this->assertEquals($this->iteratorMock, $this->subject->getReport($reportName)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php new file mode 100644 index 0000000000000..dce8089a787dc --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php @@ -0,0 +1,257 @@ +resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionMock = $this->getMockBuilder(AdapterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectMock = $this->getMockBuilder(Select::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->selectHydrator = $this->objectManagerHelper->getObject( + SelectHydrator::class, + [ + 'resourceConnection' => $this->resourceConnectionMock, + 'objectManager' => $this->objectManagerMock, + ] + ); + } + + public function testExtract() + { + $selectParts = + [ + Select::DISTINCT, + Select::COLUMNS, + Select::UNION, + Select::FROM, + Select::WHERE, + Select::GROUP, + Select::HAVING, + Select::ORDER, + Select::LIMIT_COUNT, + Select::LIMIT_OFFSET, + Select::FOR_UPDATE + ]; + + $result = []; + foreach ($selectParts as $part) { + $result[$part] = "Part"; + } + $this->selectMock->expects($this->any()) + ->method('getPart') + ->willReturn("Part"); + $this->assertEquals($this->selectHydrator->extract($this->selectMock), $result); + } + + /** + * @dataProvider recreateWithoutExpressionDataProvider + * @param array $selectParts + * @param array $parts + * @param array $partValues + */ + public function testRecreateWithoutExpression($selectParts, $parts, $partValues) + { + $this->resourceConnectionMock->expects($this->once()) + ->method('getConnection') + ->willReturn($this->connectionMock); + $this->connectionMock->expects($this->once()) + ->method('select') + ->willReturn($this->selectMock); + foreach ($parts as $key => $part) { + $this->selectMock->expects($this->at($key)) + ->method('setPart') + ->with($part, $partValues[$key]); + } + + $this->assertSame($this->selectMock, $this->selectHydrator->recreate($selectParts)); + } + + /** + * @return array + */ + public function recreateWithoutExpressionDataProvider() + { + return [ + 'Select without expressions' => [ + [ + Select::COLUMNS => [ + [ + 'table_name', + 'field_name', + 'alias', + ], + [ + 'table_name', + 'field_name_2', + 'alias_2', + ], + ] + ], + [Select::COLUMNS], + [[ + [ + 'table_name', + 'field_name', + 'alias', + ], + [ + 'table_name', + 'field_name_2', + 'alias_2', + ], + ]], + ], + ]; + } + + /** + * @dataProvider recreateWithExpressionDataProvider + * @param array $selectParts + * @param array $expectedParts + * @param \PHPUnit_Framework_MockObject_MockObject[] $expressionMocks + */ + public function testRecreateWithExpression( + array $selectParts, + array $expectedParts, + array $expressionMocks + ) { + $this->objectManagerMock + ->expects($this->exactly(count($expressionMocks))) + ->method('create') + ->with($this->isType('string'), $this->isType('array')) + ->willReturnOnConsecutiveCalls(...$expressionMocks); + $this->resourceConnectionMock + ->expects($this->once()) + ->method('getConnection') + ->with() + ->willReturn($this->connectionMock); + $this->connectionMock + ->expects($this->once()) + ->method('select') + ->with() + ->willReturn($this->selectMock); + foreach (array_keys($selectParts) as $key => $partName) { + $this->selectMock + ->expects($this->at($key)) + ->method('setPart') + ->with($partName, $expectedParts[$partName]); + } + + $this->assertSame($this->selectMock, $this->selectHydrator->recreate($selectParts)); + } + + /** + * @return array + */ + public function recreateWithExpressionDataProvider() + { + $expressionMock = $this->getMockBuilder(JsonSerializableExpression::class) + ->disableOriginalConstructor() + ->getMock(); + + return [ + 'Select without expressions' => [ + 'Parts' => [ + Select::COLUMNS => [ + [ + 'table_name', + 'field_name', + 'alias', + ], + [ + 'table_name', + [ + 'class' => 'Some_class', + 'arguments' => [ + 'expression' => ['some(expression)'] + ] + ], + 'alias_2', + ], + ] + ], + 'expectedParts' => [ + Select::COLUMNS => [ + [ + 'table_name', + 'field_name', + 'alias', + ], + [ + 'table_name', + $expressionMock, + 'alias_2', + ], + ] + ], + 'expectedExpressions' => [ + $expressionMock + ] + ], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php new file mode 100644 index 0000000000000..94f6ed1845c40 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php @@ -0,0 +1,228 @@ + 'value']; + + /** + * @return void + */ + protected function setUp() + { + $this->searchResultMock = $this->getMockBuilder(SearchResultInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->searchCriteriaMock = $this->getMockBuilder(SearchCriteriaInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->dataCollectionMock = $this->getMockBuilder(Collection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->filterMock = $this->getMockBuilder(Filter::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->dummyDataProvider = $this->objectManagerHelper->getObject( + DummyDataProvider::class, + [ + 'name' => $this->providerName, + 'searchResult' => $this->searchResultMock, + 'searchCriteria' => $this->searchCriteriaMock, + 'collection' => $this->dataCollectionMock, + 'data' => ['config' => $this->configData], + ] + ); + } + + /** + * @return void + */ + public function testGetName() + { + $this->assertSame($this->providerName, $this->dummyDataProvider->getName()); + } + + /** + * @return void + */ + public function testGetConfigData() + { + $this->assertSame($this->configData, $this->dummyDataProvider->getConfigData()); + $dataProvider = $this->objectManagerHelper + ->getObject( + DummyDataProvider::class, + [] + ); + $this->assertSame([], $dataProvider->getConfigData()); + } + + /** + * @return void + */ + public function testSetConfigData() + { + $configValue = ['key' => 'value']; + + $this->assertTrue($this->dummyDataProvider->setConfigData($configValue)); + $this->assertSame($configValue, $this->dummyDataProvider->getConfigData()); + } + + /** + * @return void + */ + public function testGetMeta() + { + $this->assertSame([], $this->dummyDataProvider->getMeta()); + } + + /** + * @return void + */ + public function testGetFieldMetaInfo() + { + $this->assertSame([], $this->dummyDataProvider->getFieldMetaInfo('', '')); + } + + /** + * @return void + */ + public function testGetFieldSetMetaInfo() + { + $this->assertSame([], $this->dummyDataProvider->getFieldSetMetaInfo('')); + } + + /** + * @return void + */ + public function testGetFieldsMetaInfo() + { + $this->assertSame([], $this->dummyDataProvider->getFieldsMetaInfo('')); + } + + /** + * @return void + */ + public function testGetPrimaryFieldName() + { + $this->assertSame('', $this->dummyDataProvider->getPrimaryFieldName()); + } + + /** + * @return void + */ + public function testGetRequestFieldName() + { + $this->assertSame('', $this->dummyDataProvider->getRequestFieldName()); + } + + /** + * @return void + */ + public function testGetData() + { + $this->dataCollectionMock + ->expects($this->once()) + ->method('toArray') + ->willReturn([]); + $this->assertSame([], $this->dummyDataProvider->getData()); + } + + /** + * @return void + */ + public function testAddFilter() + { + $this->assertNull($this->dummyDataProvider->addFilter($this->filterMock)); + } + + /** + * @return void + */ + public function testAddOrder() + { + $this->assertNull($this->dummyDataProvider->addOrder('', '')); + } + + /** + * @return void + */ + public function testSetLimit() + { + $this->assertNull($this->dummyDataProvider->setLimit(1, 1)); + } + + /** + * @return void + */ + public function testGetSearchCriteria() + { + $this->assertSame($this->searchCriteriaMock, $this->dummyDataProvider->getSearchCriteria()); + } + + /** + * @return void + */ + public function testGetSearchResult() + { + $this->assertSame($this->searchResultMock, $this->dummyDataProvider->getSearchResult()); + } +} diff --git a/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php b/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php new file mode 100644 index 0000000000000..eada5011a933f --- /dev/null +++ b/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php @@ -0,0 +1,259 @@ +name = $name; + $this->searchResult = $searchResult; + $this->searchCriteria = $searchCriteria; + $this->collection = $collection; + $this->data = $data; + } + + /** + * Get Data Provider name + * + * @return string + * @since 2.2.0 + */ + public function getName() + { + return $this->name; + } + + /** + * Get config data + * + * @return mixed + * @since 2.2.0 + */ + public function getConfigData() + { + return isset($this->data['config']) ? $this->data['config'] : []; + } + + /** + * Set config data + * + * @param mixed $config + * + * @return bool + * @since 2.2.0 + */ + public function setConfigData($config) + { + $this->data['config'] = $config; + + return true; + } + + /** + * @return array + * @since 2.2.0 + */ + public function getMeta() + { + return []; + } + + /** + * @param string $fieldSetName + * @param string $fieldName + * + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function getFieldMetaInfo($fieldSetName, $fieldName) + { + return []; + } + + /** + * Get field set meta info + * + * @param string $fieldSetName + * + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function getFieldSetMetaInfo($fieldSetName) + { + return []; + } + + /** + * @param string $fieldSetName + * + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function getFieldsMetaInfo($fieldSetName) + { + return []; + } + + /** + * Get primary field name + * + * @return string + * @since 2.2.0 + */ + public function getPrimaryFieldName() + { + return ''; + } + + /** + * Get field name in request + * + * @return string + * @since 2.2.0 + */ + public function getRequestFieldName() + { + return ''; + } + + /** + * Get data + * + * @return mixed + * @since 2.2.0 + */ + public function getData() + { + return $this->collection->toArray(); + } + + /** + * Add field filter to collection + * + * @param \Magento\Framework\Api\Filter $filter + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function addFilter(\Magento\Framework\Api\Filter $filter) + { + } + + /** + * Add ORDER BY to the end or to the beginning + * + * @param string $field + * @param string $direction + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function addOrder($field, $direction) + { + } + + /** + * Set Query limit + * + * @param int $offset + * @param int $size + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function setLimit($offset, $size) + { + } + + /** + * Returns search criteria + * + * @return SearchCriteriaInterface + * @since 2.2.0 + */ + public function getSearchCriteria() + { + return $this->searchCriteria; + } + + /** + * @return SearchResultInterface + * @since 2.2.0 + */ + public function getSearchResult() + { + return $this->searchResult; + } +} diff --git a/app/code/Magento/Analytics/composer.json b/app/code/Magento/Analytics/composer.json new file mode 100644 index 0000000000000..edc3443e487b6 --- /dev/null +++ b/app/code/Magento/Analytics/composer.json @@ -0,0 +1,26 @@ +{ + "name": "magento/module-analytics", + "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.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\Analytics\\": "" + } + } +} diff --git a/app/code/Magento/Analytics/docs/images/M2_MA_signup.png b/app/code/Magento/Analytics/docs/images/M2_MA_signup.png new file mode 100644 index 0000000000000000000000000000000000000000..78ed8fad92881ddc1eae7f474f3d4dd88daf2cc7 GIT binary patch literal 11422 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 V90=AE=Hb9U1sPT8YDv@J{{?EqC*uGB literal 0 HcmV?d00001 diff --git a/app/code/Magento/Analytics/docs/images/definition.png b/app/code/Magento/Analytics/docs/images/definition.png new file mode 100644 index 0000000000000000000000000000000000000000..16acc576320b0173e0078192f4c1b4bd3f1938fc GIT binary patch literal 7138 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 literal 0 HcmV?d00001 diff --git a/app/code/Magento/Analytics/docs/images/update.png b/app/code/Magento/Analytics/docs/images/update.png new file mode 100644 index 0000000000000000000000000000000000000000..149f5b5d3f9bd4f2ff6c320f07fc4361b0e45557 GIT binary patch literal 7534 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 S500OvLfY#3YDKE|pZ*_Yk)@^p literal 0 HcmV?d00001 diff --git a/app/code/Magento/Analytics/docs/images/update_request.png b/app/code/Magento/Analytics/docs/images/update_request.png new file mode 100644 index 0000000000000000000000000000000000000000..7181251e3634efcc49ddfe412c3c8d3509c93665 GIT binary patch literal 13059 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 YyR-G-9GoM?Ou!FF{h?Z=>Z3pY4PTYIk^lez literal 0 HcmV?d00001 diff --git a/app/code/Magento/Analytics/etc/acl.xml b/app/code/Magento/Analytics/etc/acl.xml new file mode 100644 index 0000000000000..bf2251895f929 --- /dev/null +++ b/app/code/Magento/Analytics/etc/acl.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Analytics/etc/adminhtml/di.xml b/app/code/Magento/Analytics/etc/adminhtml/di.xml new file mode 100644 index 0000000000000..5e305e70e5ad3 --- /dev/null +++ b/app/code/Magento/Analytics/etc/adminhtml/di.xml @@ -0,0 +1,16 @@ + + + + + + + Magento\Analytics\Model\System\Message\NotificationAboutFailedSubscription + + + + diff --git a/app/code/Magento/Analytics/etc/adminhtml/menu.xml b/app/code/Magento/Analytics/etc/adminhtml/menu.xml new file mode 100644 index 0000000000000..915211c4bb85e --- /dev/null +++ b/app/code/Magento/Analytics/etc/adminhtml/menu.xml @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/app/code/Magento/Analytics/etc/adminhtml/routes.xml b/app/code/Magento/Analytics/etc/adminhtml/routes.xml new file mode 100644 index 0000000000000..0ae2762dacc5f --- /dev/null +++ b/app/code/Magento/Analytics/etc/adminhtml/routes.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/code/Magento/Analytics/etc/adminhtml/system.xml b/app/code/Magento/Analytics/etc/adminhtml/system.xml new file mode 100644 index 0000000000000..32d493451ca61 --- /dev/null +++ b/app/code/Magento/Analytics/etc/adminhtml/system.xml @@ -0,0 +1,47 @@ + + + + +
+ + general + Magento_Analytics::analytics_settings + + + For more information, view details or see our + terms and conditions.]]> + + + Magento\Config\Model\Config\Source\Enabledisable + Magento\Analytics\Model\Config\Backend\Enabled + Magento\Analytics\Block\Adminhtml\System\Config\SubscriptionStatusLabel + analytics/subscription/enabled + + + + Magento\Analytics\Model\Config\Source\Vertical + Magento\Analytics\Model\Config\Backend\Vertical + + + + Magento\Analytics\Block\Adminhtml\System\Config\CollectionTimeLabel + Magento\Analytics\Model\Config\Backend\CollectionTime + + + + Learn more about BI Essentials tier.]]> + Magento\Analytics\Block\Adminhtml\System\Config\AdditionalComment + + +
+
+
diff --git a/app/code/Magento/Analytics/etc/analytics.xml b/app/code/Magento/Analytics/etc/analytics.xml new file mode 100644 index 0000000000000..77ebe751a31cf --- /dev/null +++ b/app/code/Magento/Analytics/etc/analytics.xml @@ -0,0 +1,50 @@ + + + + + + + + modules + + + + + + + + + + + + + + stores + + + + + + + + + websites + + + + + + + + + groups + + + + + diff --git a/app/code/Magento/Analytics/etc/analytics.xsd b/app/code/Magento/Analytics/etc/analytics.xsd new file mode 100644 index 0000000000000..2506e3d6a6a9a --- /dev/null +++ b/app/code/Magento/Analytics/etc/analytics.xsd @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + File name attribute can has only [a-zA-Z0-9/_]. + + + + + + + + + + Value is required. + + + + + + + diff --git a/app/code/Magento/Analytics/etc/config.xml b/app/code/Magento/Analytics/etc/config.xml new file mode 100644 index 0000000000000..b6194ba12993f --- /dev/null +++ b/app/code/Magento/Analytics/etc/config.xml @@ -0,0 +1,25 @@ + + + + + + + https://advancedreporting.rjmetrics.com/signup + https://advancedreporting.rjmetrics.com/update + https://dashboard.rjmetrics.com/v2/magento/signup + https://advancedreporting.rjmetrics.com/otp + https://advancedreporting.rjmetrics.com/report + https://advancedreporting.rjmetrics.com/report + + Magento Analytics user + + 02,00,00 + + + + diff --git a/app/code/Magento/Analytics/etc/crontab.xml b/app/code/Magento/Analytics/etc/crontab.xml new file mode 100644 index 0000000000000..a4beef0359540 --- /dev/null +++ b/app/code/Magento/Analytics/etc/crontab.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/code/Magento/Analytics/etc/di.xml b/app/code/Magento/Analytics/etc/di.xml new file mode 100644 index 0000000000000..09efd7c36ad83 --- /dev/null +++ b/app/code/Magento/Analytics/etc/di.xml @@ -0,0 +1,262 @@ + + + + + + + + + + + + + + + Magento\Analytics\Model\Connector\SignUpCommand + Magento\Analytics\Model\Connector\UpdateCommand + Magento\Analytics\Model\Connector\NotifyDataChangedCommand + + + + + + Magento\Config\Model\ResourceModel\Config\Data + + + + + + Magento\Analytics\ReportXml\Config\Data + + + + + Magento\Analytics\ReportXml\Config\Reader + Magento_Analytics_ReportXml_CacheId + + + + + urn:magento:module:Magento_Analytics:etc/reports.xsd + + + + + Magento\Analytics\ReportXml\Config\Converter\Xml + Magento\Analytics\ReportXml\Config\SchemaLocator + reports.xml + + name + + name + alias + + name + name + + glue + + attribute + operator + + + glue + + attribute + operator + + + glue + + attribute + operator + + glue + + attribute + operator + + + + + + + + Magento\Analytics\ReportXml\Config\Reader\Xml + + + + + + + Magento\Analytics\Model\Config\Data + + + + + Magento\Analytics\Model\Config\Reader + Magento_Analytics_CacheId + + + + + urn:magento:module:Magento_Analytics:etc/analytics.xsd + + + + + Magento\Analytics\ReportXml\Config\Converter\Xml + Magento\Analytics\Model\Config\SchemaLocator + analytics.xml + + name + + + + + + + + Magento\Analytics\ReportXml\DB\Assembler\FromAssembler + Magento\Analytics\ReportXml\DB\Assembler\FilterAssembler + Magento\Analytics\ReportXml\DB\Assembler\JoinAssembler + + + + + + + Magento\Analytics\Model\Config\Reader\Xml + + + + + + + web/unsecure/base_url + currency/options/base + general/locale/timezone + general/country/default + carriers/dhl/title + carriers/dhl/active + carriers/fedex/title + carriers/fedex/active + carriers/flatrate/title + carriers/flatrate/active + carriers/tablerate/title + carriers/tablerate/active + carriers/freeshipping/title + carriers/freeshipping/active + carriers/ups/title + carriers/ups/active + carriers/usps/title + carriers/usps/active + payment/free/title + payment/free/active + payment/checkmo/title + payment/checkmo/active + payment/purchaseorder/title + payment/purchaseorder/active + payment/banktransfer/title + payment/banktransfer/active + payment/cashondelivery/title + payment/cashondelivery/active + payment/authorizenet_directpost/title + payment/authorizenet_directpost/active + payment/paypal_billing_agreement/title + payment/paypal_billing_agreement/active + payment/braintree/title + payment/braintree/active + payment/braintree_paypal/title + payment/braintree_paypal/active + analytics/general/vertical + + + + + + + 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 + + + + + + + + + + \Magento\Analytics\Model\Connector\ResponseHandler\SignUp + + + + + + + Magento\Analytics\Model\Connector\ResponseHandler\Update + Magento\Analytics\Model\Connector\ResponseHandler\ReSignUp + + + + + + + Magento\Analytics\Model\Connector\ResponseHandler\OTP + Magento\Analytics\Model\Connector\ResponseHandler\ReSignUp + + + + + + + Magento\Analytics\Model\Connector\ResponseHandler\ReSignUp + + + + + + SignUpResponseResolver + + + + + UpdateResponseResolver + + + + + OtpResponseResolver + + + + + NotifyDataChangedResponseResolver + + + diff --git a/app/code/Magento/Analytics/etc/module.xml b/app/code/Magento/Analytics/etc/module.xml new file mode 100644 index 0000000000000..32ee5d23a4d86 --- /dev/null +++ b/app/code/Magento/Analytics/etc/module.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/app/code/Magento/Analytics/etc/reports.xml b/app/code/Magento/Analytics/etc/reports.xml new file mode 100644 index 0000000000000..8a43658670293 --- /dev/null +++ b/app/code/Magento/Analytics/etc/reports.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/Analytics/etc/reports.xsd b/app/code/Magento/Analytics/etc/reports.xsd new file mode 100644 index 0000000000000..d0ba4068244fe --- /dev/null +++ b/app/code/Magento/Analytics/etc/reports.xsd @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Analytics/etc/webapi.xml b/app/code/Magento/Analytics/etc/webapi.xml new file mode 100644 index 0000000000000..8252d039f1d03 --- /dev/null +++ b/app/code/Magento/Analytics/etc/webapi.xml @@ -0,0 +1,16 @@ + + + + + + + + + + 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/Analytics/registration.php b/app/code/Magento/Analytics/registration.php new file mode 100644 index 0000000000000..58d3688b7491d --- /dev/null +++ b/app/code/Magento/Analytics/registration.php @@ -0,0 +1,11 @@ + + + + + + + + + + + + diff --git a/app/code/Magento/Analytics/view/adminhtml/templates/dashboard/section.phtml b/app/code/Magento/Analytics/view/adminhtml/templates/dashboard/section.phtml new file mode 100644 index 0000000000000..a22c603b2a8b3 --- /dev/null +++ b/app/code/Magento/Analytics/view/adminhtml/templates/dashboard/section.phtml @@ -0,0 +1,28 @@ + + +
+
+
+ escapeHtml(__('Advanced Reporting')) ?> +
+
+ escapeHtml(__('Gain new insights and take command of your business\' performance,' . + ' using our dynamic product, order, and customer reports tailored to your customer data.')) ?> +
+
+ +
diff --git a/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_form.xml b/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_form.xml new file mode 100644 index 0000000000000..b44974b32cffa --- /dev/null +++ b/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_form.xml @@ -0,0 +1,247 @@ + + +
+ + + analytics_subscription_form.analytics_subscription_form_data_source + + Analytics Subscription + templates/form/collapsible + + + analytics_subscription_form + true + simple + data + + analytics_subscription_form.analytics_subscription_form_data_source + + + + + + + + + + + + + Magento_Ui/js/form/provider + + + + + + + + + false + + + + + + + actionCancel + true + + + + + + + + + + +
+ + + + + + + advanced-reports-subscription-text + 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.

]]> +
+
+
+
+ + + + + + + + + + + + + 1 + + + + + true + + analytics_subscription_checkbox + + + + + + Learn more.]]> + + 1 + 0 + + + + + + +
+
+ + + actionCancel + + + + + + + + + + + + + + + advanced-reports-subscription-text + 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/Analytics/view/adminhtml/web/js/modal/modal-component.js b/app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js new file mode 100644 index 0000000000000..9dee8d0c8e9ce --- /dev/null +++ b/app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js @@ -0,0 +1,66 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'jquery', + 'Magento_Ui/js/modal/modal-component', + 'Magento_Ui/js/modal/alert', + 'mage/translate' +], function ($, Modal, alert, $t) { + 'use strict'; + + return Modal.extend({ + defaults: { + postponeOptions: {}, + imports: { + postponeUrl: '${ $.provider }:postpone_url' + }, + modules: { + form: '${ $.parentName }' + } + }, + + /** + * Send request to postpone modal appearance for a certain time. + * + * @param {Object} options - additional request options. + */ + sendPostponeRequest: function (options) { + var self = this, + data = $.extend(this.form().source.data, options); + + $.ajax({ + type: 'POST', + url: this.postponeUrl, + data: data, + showLoader: true + }).done(function (xhr) { + if (xhr.error) { + self.onError(xhr); + } + }).fail(this.onError); + }, + + /** + * Error handler. + * + * @param {Object} xhr - request result. + */ + onError: function (xhr) { + if (xhr.statusText === 'abort') { + return; + } + + alert({ + content: xhr.message || $t('An error occurred while subscription process.') + }); + }, + + /** @inheritdoc */ + actionCancel: function () { + this.sendPostponeRequest(this.postponeOptions); + this.closeModal(); + } + }); +}); diff --git a/app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html b/app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html new file mode 100644 index 0000000000000..784e16d72c3f5 --- /dev/null +++ b/app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html @@ -0,0 +1,13 @@ + +
+ + +
+ +
+
diff --git a/app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html b/app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html new file mode 100644 index 0000000000000..297867c60c1e4 --- /dev/null +++ b/app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html @@ -0,0 +1,17 @@ + +
+ + +
diff --git a/app/code/Magento/CatalogAnalytics/LICENSE.txt b/app/code/Magento/CatalogAnalytics/LICENSE.txt new file mode 100644 index 0000000000000..49525fd99da9c --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/LICENSE.txt @@ -0,0 +1,48 @@ + +Open Software License ("OSL") v. 3.0 + +This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Open Software License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/CatalogAnalytics/LICENSE_AFL.txt b/app/code/Magento/CatalogAnalytics/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/CatalogAnalytics/README.md b/app/code/Magento/CatalogAnalytics/README.md new file mode 100644 index 0000000000000..df125446117a3 --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/README.md @@ -0,0 +1,3 @@ +# Magento_CatalogAnalytics module + +The Magento_CatalogAnalytics module configures data definitions for a data collection related to the Catalog module entities to be used in [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html). diff --git a/app/code/Magento/CatalogAnalytics/composer.json b/app/code/Magento/CatalogAnalytics/composer.json new file mode 100644 index 0000000000000..6cda52197f80a --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/composer.json @@ -0,0 +1,23 @@ +{ + "name": "magento/module-catalog-analytics", + "description": "N/A", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/framework": "100.2.*", + "magento/module-catalog": "101.1.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\CatalogAnalytics\\": "" + } + } +} diff --git a/app/code/Magento/CatalogAnalytics/etc/analytics.xml b/app/code/Magento/CatalogAnalytics/etc/analytics.xml new file mode 100644 index 0000000000000..22d1f2c7d7776 --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/etc/analytics.xml @@ -0,0 +1,18 @@ + + + + + + + + products + + + + + diff --git a/app/code/Magento/CatalogAnalytics/etc/module.xml b/app/code/Magento/CatalogAnalytics/etc/module.xml new file mode 100644 index 0000000000000..7974598e17a59 --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/etc/module.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/CatalogAnalytics/etc/reports.xml b/app/code/Magento/CatalogAnalytics/etc/reports.xml new file mode 100644 index 0000000000000..5dae3ef90d7b2 --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/etc/reports.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/CatalogAnalytics/registration.php b/app/code/Magento/CatalogAnalytics/registration.php new file mode 100644 index 0000000000000..77d6ce154b658 --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/registration.php @@ -0,0 +1,11 @@ +" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/CustomerAnalytics/LICENSE_AFL.txt b/app/code/Magento/CustomerAnalytics/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/CustomerAnalytics/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/CustomerAnalytics/README.md b/app/code/Magento/CustomerAnalytics/README.md new file mode 100644 index 0000000000000..8c64ce97629da --- /dev/null +++ b/app/code/Magento/CustomerAnalytics/README.md @@ -0,0 +1,3 @@ +# Magento_CustomerAnalytics module + +The Magento_CustomerAnalytics module configures data definitions for a data collection related to the Customer module entities to be used in [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html). diff --git a/app/code/Magento/CustomerAnalytics/composer.json b/app/code/Magento/CustomerAnalytics/composer.json new file mode 100644 index 0000000000000..36e7492decc50 --- /dev/null +++ b/app/code/Magento/CustomerAnalytics/composer.json @@ -0,0 +1,23 @@ +{ + "name": "magento/module-customer-analytics", + "description": "N/A", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/framework": "100.2.*", + "magento/module-customer": "100.2.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\CustomerAnalytics\\": "" + } + } +} diff --git a/app/code/Magento/CustomerAnalytics/etc/analytics.xml b/app/code/Magento/CustomerAnalytics/etc/analytics.xml new file mode 100644 index 0000000000000..5e47040c2f3bd --- /dev/null +++ b/app/code/Magento/CustomerAnalytics/etc/analytics.xml @@ -0,0 +1,18 @@ + + + + + + + + customers + + + + + diff --git a/app/code/Magento/CustomerAnalytics/etc/module.xml b/app/code/Magento/CustomerAnalytics/etc/module.xml new file mode 100644 index 0000000000000..adc4f8dd849c2 --- /dev/null +++ b/app/code/Magento/CustomerAnalytics/etc/module.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/CustomerAnalytics/etc/reports.xml b/app/code/Magento/CustomerAnalytics/etc/reports.xml new file mode 100644 index 0000000000000..b3300b0127709 --- /dev/null +++ b/app/code/Magento/CustomerAnalytics/etc/reports.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/app/code/Magento/CustomerAnalytics/registration.php b/app/code/Magento/CustomerAnalytics/registration.php new file mode 100644 index 0000000000000..e4c3348182877 --- /dev/null +++ b/app/code/Magento/CustomerAnalytics/registration.php @@ -0,0 +1,11 @@ +" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/QuoteAnalytics/LICENSE_AFL.txt b/app/code/Magento/QuoteAnalytics/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/QuoteAnalytics/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/QuoteAnalytics/README.md b/app/code/Magento/QuoteAnalytics/README.md new file mode 100644 index 0000000000000..d4adcc9313229 --- /dev/null +++ b/app/code/Magento/QuoteAnalytics/README.md @@ -0,0 +1,3 @@ +# Magento_QuoteAnalytics + +The Magento_QuoteAnalytics module configures data definitions for a data collection related to the Quote module entities to be used in [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html). diff --git a/app/code/Magento/QuoteAnalytics/composer.json b/app/code/Magento/QuoteAnalytics/composer.json new file mode 100644 index 0000000000000..7f38e489ab0b0 --- /dev/null +++ b/app/code/Magento/QuoteAnalytics/composer.json @@ -0,0 +1,23 @@ +{ + "name": "magento/module-quote-analytics", + "description": "N/A", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/framework": "100.2.*", + "magento/module-quote": "100.2.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\QuoteAnalytics\\": "" + } + } +} diff --git a/app/code/Magento/QuoteAnalytics/etc/analytics.xml b/app/code/Magento/QuoteAnalytics/etc/analytics.xml new file mode 100644 index 0000000000000..cc4dfb6364904 --- /dev/null +++ b/app/code/Magento/QuoteAnalytics/etc/analytics.xml @@ -0,0 +1,18 @@ + + + + + + + + quotes + + + + + diff --git a/app/code/Magento/QuoteAnalytics/etc/module.xml b/app/code/Magento/QuoteAnalytics/etc/module.xml new file mode 100644 index 0000000000000..d72e36b748748 --- /dev/null +++ b/app/code/Magento/QuoteAnalytics/etc/module.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/QuoteAnalytics/etc/reports.xml b/app/code/Magento/QuoteAnalytics/etc/reports.xml new file mode 100644 index 0000000000000..f57012df23389 --- /dev/null +++ b/app/code/Magento/QuoteAnalytics/etc/reports.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/QuoteAnalytics/registration.php b/app/code/Magento/QuoteAnalytics/registration.php new file mode 100644 index 0000000000000..19718c3cf2adf --- /dev/null +++ b/app/code/Magento/QuoteAnalytics/registration.php @@ -0,0 +1,11 @@ +" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/ReviewAnalytics/LICENSE_AFL.txt b/app/code/Magento/ReviewAnalytics/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/ReviewAnalytics/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/ReviewAnalytics/README.md b/app/code/Magento/ReviewAnalytics/README.md new file mode 100644 index 0000000000000..b078083dfb7dc --- /dev/null +++ b/app/code/Magento/ReviewAnalytics/README.md @@ -0,0 +1,3 @@ +# Magento_ReviewAnalytics module + +The Magento_ReviewAnalytics module configures data definitions for a data collection related to the Review module entities to be used in [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html). diff --git a/app/code/Magento/ReviewAnalytics/composer.json b/app/code/Magento/ReviewAnalytics/composer.json new file mode 100644 index 0000000000000..b31c420e181bf --- /dev/null +++ b/app/code/Magento/ReviewAnalytics/composer.json @@ -0,0 +1,23 @@ +{ + "name": "magento/module-review-analytics", + "description": "N/A", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/framework": "100.2.*", + "magento/module-review": "100.2.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\ReviewAnalytics\\": "" + } + } +} diff --git a/app/code/Magento/ReviewAnalytics/etc/analytics.xml b/app/code/Magento/ReviewAnalytics/etc/analytics.xml new file mode 100644 index 0000000000000..cd5d1b2c1af4c --- /dev/null +++ b/app/code/Magento/ReviewAnalytics/etc/analytics.xml @@ -0,0 +1,27 @@ + + + + + + + + reviews + + + + + + + + + rating_option_votes + + + + + diff --git a/app/code/Magento/ReviewAnalytics/etc/module.xml b/app/code/Magento/ReviewAnalytics/etc/module.xml new file mode 100644 index 0000000000000..65df87bac4af1 --- /dev/null +++ b/app/code/Magento/ReviewAnalytics/etc/module.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/ReviewAnalytics/etc/reports.xml b/app/code/Magento/ReviewAnalytics/etc/reports.xml new file mode 100644 index 0000000000000..8dd508983aced --- /dev/null +++ b/app/code/Magento/ReviewAnalytics/etc/reports.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/ReviewAnalytics/registration.php b/app/code/Magento/ReviewAnalytics/registration.php new file mode 100644 index 0000000000000..6b795ca04c61b --- /dev/null +++ b/app/code/Magento/ReviewAnalytics/registration.php @@ -0,0 +1,11 @@ +" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/SalesAnalytics/LICENSE_AFL.txt b/app/code/Magento/SalesAnalytics/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/SalesAnalytics/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/SalesAnalytics/README.md b/app/code/Magento/SalesAnalytics/README.md new file mode 100644 index 0000000000000..70f456c97d4b3 --- /dev/null +++ b/app/code/Magento/SalesAnalytics/README.md @@ -0,0 +1,3 @@ +# Magento_SalesAnalytics module + +The Magento_SalesAnalytics module configures data definitions for a data collection related to the Sales module entities to be used in [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html). diff --git a/app/code/Magento/SalesAnalytics/composer.json b/app/code/Magento/SalesAnalytics/composer.json new file mode 100644 index 0000000000000..7c9270a503b0d --- /dev/null +++ b/app/code/Magento/SalesAnalytics/composer.json @@ -0,0 +1,23 @@ +{ + "name": "magento/module-sales-analytics", + "description": "N/A", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/framework": "100.2.*", + "magento/module-sales": "100.2.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\SalesAnalytics\\": "" + } + } +} diff --git a/app/code/Magento/SalesAnalytics/etc/analytics.xml b/app/code/Magento/SalesAnalytics/etc/analytics.xml new file mode 100644 index 0000000000000..be6c4dfde9b19 --- /dev/null +++ b/app/code/Magento/SalesAnalytics/etc/analytics.xml @@ -0,0 +1,36 @@ + + + + + + + + orders + + + + + + + + + order_items + + + + + + + + + order_addresses + + + + + diff --git a/app/code/Magento/SalesAnalytics/etc/module.xml b/app/code/Magento/SalesAnalytics/etc/module.xml new file mode 100644 index 0000000000000..7a15075a4bc21 --- /dev/null +++ b/app/code/Magento/SalesAnalytics/etc/module.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/SalesAnalytics/etc/reports.xml b/app/code/Magento/SalesAnalytics/etc/reports.xml new file mode 100644 index 0000000000000..bb6bdb800e9bf --- /dev/null +++ b/app/code/Magento/SalesAnalytics/etc/reports.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/SalesAnalytics/registration.php b/app/code/Magento/SalesAnalytics/registration.php new file mode 100644 index 0000000000000..eff2c5b1a2c05 --- /dev/null +++ b/app/code/Magento/SalesAnalytics/registration.php @@ -0,0 +1,11 @@ +" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/WishlistAnalytics/LICENSE_AFL.txt b/app/code/Magento/WishlistAnalytics/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/WishlistAnalytics/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/WishlistAnalytics/README.md b/app/code/Magento/WishlistAnalytics/README.md new file mode 100644 index 0000000000000..999fc835626da --- /dev/null +++ b/app/code/Magento/WishlistAnalytics/README.md @@ -0,0 +1,3 @@ +# Magento_WishlistAnalytics module + +The Magento_WishlistAnalytics module configures data definitions for a data collection related to the Wishlist module entities to be used in [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html). diff --git a/app/code/Magento/WishlistAnalytics/composer.json b/app/code/Magento/WishlistAnalytics/composer.json new file mode 100644 index 0000000000000..20f414c00c320 --- /dev/null +++ b/app/code/Magento/WishlistAnalytics/composer.json @@ -0,0 +1,23 @@ +{ + "name": "magento/module-wishlist-analytics", + "description": "N/A", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/framework": "100.2.*", + "magento/module-wishlist": "100.2.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\WishlistAnalytics\\": "" + } + } +} diff --git a/app/code/Magento/WishlistAnalytics/etc/analytics.xml b/app/code/Magento/WishlistAnalytics/etc/analytics.xml new file mode 100644 index 0000000000000..0b2531fe0df67 --- /dev/null +++ b/app/code/Magento/WishlistAnalytics/etc/analytics.xml @@ -0,0 +1,27 @@ + + + + + + + + wishlists + + + + + + + + + wishlist_items + + + + + diff --git a/app/code/Magento/WishlistAnalytics/etc/module.xml b/app/code/Magento/WishlistAnalytics/etc/module.xml new file mode 100644 index 0000000000000..159ed86ee171a --- /dev/null +++ b/app/code/Magento/WishlistAnalytics/etc/module.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/WishlistAnalytics/etc/reports.xml b/app/code/Magento/WishlistAnalytics/etc/reports.xml new file mode 100644 index 0000000000000..0125fa93f815a --- /dev/null +++ b/app/code/Magento/WishlistAnalytics/etc/reports.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/WishlistAnalytics/registration.php b/app/code/Magento/WishlistAnalytics/registration.php new file mode 100644 index 0000000000000..eacf1e0d78bcb --- /dev/null +++ b/app/code/Magento/WishlistAnalytics/registration.php @@ -0,0 +1,11 @@ +objectManager = Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Analytics/_files/create_link.php + */ + public function testGetAll() + { + $objectManager = Bootstrap::getObjectManager(); + + /** + * @var $fileInfoManager FileInfoManager + */ + $fileInfoManager = $objectManager->create(FileInfoManager::class); + + $storeManager = $objectManager->create(StoreManagerInterface::class); + + $fileInfo = $fileInfoManager->load(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => static::RESOURCE_PATH, + 'httpMethod' => Request::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => static::SERVICE_NAME, + 'serviceVersion' => static::SERVICE_VERSION, + 'operation' => static::SERVICE_NAME . 'Get', + ], + ]; + if (!$this->isTestBaseUrlSecure()) { + try { + $this->_webApiCall($serviceInfo); + } catch (\Exception $e) { + $this->assertContains( + 'Operation allowed only in HTTPS', + $e->getMessage() + ); + return; + } + $this->fail("Exception 'Operation allowed only in HTTPS' should be thrown"); + } else { + $response = $this->_webApiCall($serviceInfo); + $this->assertEquals(2, count($response)); + $this->assertEquals( + base64_encode($fileInfo->getInitializationVector()), + $response['initialization_vector'] + ); + $this->assertEquals( + $storeManager->getStore()->getBaseUrl( + UrlInterface::URL_TYPE_MEDIA + ) . $fileInfo->getPath(), + $response['url'] + ); + } + } + + /** + * @return bool + */ + private function isTestBaseUrlSecure() + { + return strpos('https://', TESTS_BASE_URL) !== false; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php b/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php new file mode 100644 index 0000000000000..81724e735f269 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php @@ -0,0 +1,55 @@ +configuration = $configuration; + } + + /** + * Cancel subscription for functional tests + * + * @param AbstractState $state + * @return bool + * @throws \Exception + */ + public function execute(AbstractState $state) + { + $url = $_ENV['app_backend_url'] . 'analytics/subscription/postpone'; + $curl = new BackendDecorator(new CurlTransport(), $this->configuration); + $curl->write($url, []); + $response = $curl->read(); + $curl->close(); + if (isset($response['success'])) { + return $response['success']; + } + return false; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/ReportsSectionBlock.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/ReportsSectionBlock.php new file mode 100644 index 0000000000000..1c7edaaac86f0 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/ReportsSectionBlock.php @@ -0,0 +1,31 @@ +_rootElement->find($this->advancedReportingButton)->click(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php new file mode 100644 index 0000000000000..0cbb853167f30 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php @@ -0,0 +1,99 @@ +_rootElement->find($this->checkbox, Locator::SELECTOR_CSS, 'checkbox')->setValue('Yes'); + } + + /** + * Disable checkbox in modal window. + * + * @return void + */ + public function disableCheckbox() + { + $this->_rootElement->find($this->checkbox, Locator::SELECTOR_CSS, 'checkbox')->setValue('No'); + } + + /** + * Enable Advanced Reporting on a subscription popup. + * + * @return void + */ + public function acceptAdvancedReporting() + { + $this->waitModalAnimationFinished(); + $this->_rootElement->find($this->acceptReportingButton)->click(); + $this->waitForElementNotVisible($this->loadingMask); + } + + /** + * Disable Advanced Reporting on a subscription popup. + * + * @return void + */ + public function declineAdvancedReporting() + { + $this->waitModalAnimationFinished(); + $this->_rootElement->find($this->declineReportingButton)->click(); + $this->waitForElementNotVisible($this->loadingMask); + } + + /** + * Skip subscription popup. + * + * @return void + */ + public function skipAdvancedReporting() + { + $this->waitModalAnimationFinished(); + $this->_rootElement->find($this->skipReportingButton)->click(); + $this->waitForElementNotVisible($this->loadingMask); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/System/Config/AnalyticsForm.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/System/Config/AnalyticsForm.php new file mode 100644 index 0000000000000..07b62a9518ae4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/System/Config/AnalyticsForm.php @@ -0,0 +1,158 @@ + td.value > p > span'; + + /** + * @var string + */ + private $submitButton = '#save'; + + /** + * @var string + */ + private $analyticsVertical = '#analytics_general_vertical'; + + /** + * @var string + */ + private $analyticsVerticalScope = '#row_analytics_general_vertical span[data-config-scope="[WEBSITE]"]'; + + /** + * @var string + */ + private $sendDataTimeHh = '#row_analytics_general_collection_time > td.value > select:nth-child(2)'; + + /** + * @var string + */ + private $sendDataTimeMm = '#row_analytics_general_collection_time > td.value > select:nth-child(3)'; + + /** + * @var string + */ + private $sendDataTimeSs = '#row_analytics_general_collection_time > td.value > select:nth-child(4)'; + + /** + * @var string + */ + private $timeZone = + '#row_analytics_general_collection_time > td.value > p > span'; + + /** + * @return array|string + */ + public function isAnalyticsEnabled() + { + return $this->_rootElement->find($this->analyticsStatus, Locator::SELECTOR_CSS)->getValue(); + } + + /** + * @param string $state + * @return array|string + */ + public function analyticsToggle($state = 'Enable') + { + return $this->_rootElement->find($this->analyticsStatus, Locator::SELECTOR_CSS, 'select')->setValue($state); + } + + /** + * @return array|string + */ + public function saveConfig() + { + return $this->browser->find($this->submitButton)->click(); + } + + /** + * @return array|string + */ + public function getAnalyticsStatus() + { + return $this->_rootElement->find($this->analyticsStatusLabel, Locator::SELECTOR_CSS)->getText(); + } + + /** + * @param string $vertical + * @return array|string + */ + public function setAnalyticsVertical($vertical) + { + return $this->_rootElement->find($this->analyticsVertical, Locator::SELECTOR_CSS, 'select') + ->setValue($vertical); + } + + /** + * @param string $hh + * @param string $mm + * @return $this + */ + public function setTimeOfDayToSendData($hh, $mm) + { + $this->_rootElement->find($this->sendDataTimeHh, Locator::SELECTOR_CSS, 'select') + ->setValue($hh); + $this->_rootElement->find($this->sendDataTimeMm, Locator::SELECTOR_CSS, 'select') + ->setValue($mm); + return $this; + } + + /** + * @return string + */ + public function getTimeOfDayToSendDate() + { + $hh = $this->_rootElement->find($this->sendDataTimeHh, Locator::SELECTOR_CSS, 'select') + ->getValue(); + $mm = $this->_rootElement->find($this->sendDataTimeMm, Locator::SELECTOR_CSS, 'select') + ->getValue(); + $ss = $this->_rootElement->find($this->sendDataTimeSs, Locator::SELECTOR_CSS, 'select') + ->getValue(); + return sprintf('%s, %s, %s', $hh, $mm, $ss); + } + + /** + * @return mixed + */ + public function getTimeZone() + { + return $this->_rootElement->find($this->timeZone, Locator::SELECTOR_CSS) + ->getText(); + } + + /** + * @return array|string + */ + public function getAnalyticsVertical() + { + return $this->_rootElement->find($this->analyticsVertical, Locator::SELECTOR_CSS)->getValue(); + } + + /** + * @return array|string + */ + public function getAnalyticsVerticalScope() + { + return $this->_rootElement->find($this->analyticsVerticalScope, Locator::SELECTOR_CSS)->isVisible(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPage.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPage.php new file mode 100644 index 0000000000000..de379aea85fa7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPage.php @@ -0,0 +1,53 @@ +browser = $browser; + $this->browser->selectWindow(); + \PHPUnit_Framework_Assert::assertTrue( + $this->browser->waitUntil( + function () use ($advancedReportingLink) { + return ($this->browser->getUrl() === $advancedReportingLink) ? true : null; + } + ), + 'Advanced Reporting Sign Up page was not opened by link.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Advanced Reporting Sign Up page is opened by link'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertBIEssentialsLink.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertBIEssentialsLink.php new file mode 100644 index 0000000000000..010d9c446819d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertBIEssentialsLink.php @@ -0,0 +1,87 @@ +browser = $browser; + $count = 0; + $isVisible = false; + do { + try { + $this->browser->selectWindow(); + $isVisible = $this->browser->waitUntil(function () use ($businessIntelligenceLink) { + return ($this->browser->getUrl() === $businessIntelligenceLink) ?: null; + }); + break; + } catch (\Throwable $e) { + $dashboard->open(); + $dashboard->getMenuBlock()->navigate($menuItem, $waitMenuItemNotVisible); + $count++; + } + } while ($count < self::MAX_TRY_COUNT); + + \PHPUnit_Framework_Assert::assertTrue( + $isVisible, + "BI Essentials Sign Up page was not opened by link.\n + Actual link is '{$this->browser->getUrl()}'\n + Expected link is '$businessIntelligenceLink'" + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'BI Essentials Sign Up page is opened by link'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php new file mode 100644 index 0000000000000..daeed6a66cfa4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php @@ -0,0 +1,49 @@ +Configuration>General>Analytics->General menu. + */ +class AssertConfigAnalyticsDisabled extends AbstractConstraint +{ + /** + * Assert Analytics is disabled in Stores > Configuration > General > Analytics menu. + * + * @param ConfigAnalytics $configAnalytics + * @param OpenAnalyticsConfigStep $openAnalyticsConfigStep + * @return void + */ + public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsConfigStep $openAnalyticsConfigStep) + { + $openAnalyticsConfigStep->run(); + + \PHPUnit_Framework_Assert::assertFalse( + (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), + 'Magento Analytics is not disabled.' + ); + \PHPUnit_Framework_Assert::assertEquals( + $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), + 'Subscription status: Disabled', + 'Magento Analytics status is not disabled.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Magento Analytics is disabled in Stores > Configuration > General > Analytics > General menu' + . ' and has Disabled status.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php new file mode 100644 index 0000000000000..eb699105e1906 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php @@ -0,0 +1,50 @@ + Configuration > General > Analytics > General menu. + */ +class AssertConfigAnalyticsEnabled extends AbstractConstraint +{ + /** + * Assert Analytics is enabled in Stores > Configuration > General > Analytics menu. + * + * @param ConfigAnalytics $configAnalytics + * @param OpenAnalyticsConfigStep $openAnalyticsConfigStep + * @return void + */ + public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsConfigStep $openAnalyticsConfigStep) + { + $openAnalyticsConfigStep->run(); + + \PHPUnit_Framework_Assert::assertTrue( + (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), + 'Magento Analytics is not enabled.' + ); + + \PHPUnit_Framework_Assert::assertEquals( + $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), + 'Subscription status: Pending', + 'Magento Analytics status is not pending.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Magento Analytics is enabled and has Pending status in' + . ' Stores > Configuration > General > Analytics > General menu.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php new file mode 100644 index 0000000000000..e624b49ff38dc --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php @@ -0,0 +1,54 @@ +run(); + + $configAnalytics->getAnalyticsForm()->analyticsToggle(); + $configAnalytics->getAnalyticsForm()->setAnalyticsVertical($vertical); + $configAnalytics->getAnalyticsForm()->saveConfig(); + + \PHPUnit_Framework_Assert::assertTrue( + $systemConfigPage->getMessagesBlock()->assertSuccessMessage(), + 'Sending data to the Analytics is not saved.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Sending data to the Analytics is saved.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsSendingTimeAndZone.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsSendingTimeAndZone.php new file mode 100644 index 0000000000000..1de9405e61f21 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsSendingTimeAndZone.php @@ -0,0 +1,52 @@ +run(); + + \PHPUnit_Framework_Assert::assertEquals( + 'Eastern European Standard Time (Europe/Kiev)', + $configAnalytics->getAnalyticsForm()->getTimeZone() + ); + + \PHPUnit_Framework_Assert::assertEquals( + sprintf('%s, %s, 00', $hh, $mm), + $configAnalytics->getAnalyticsForm()->getTimeOfDayToSendDate() + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Time and TimeZone are correct!'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php new file mode 100644 index 0000000000000..3793292653cbf --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php @@ -0,0 +1,39 @@ + Configuration > General > Analytics > General menu. + */ +class AssertConfigAnalyticsVerticalScope extends AbstractConstraint +{ + /** + * Assert Analytics vertical scope is website in Stores > Configuration > General > Analytics menu. + * + * @param ConfigAnalytics $configAnalytics + */ + public function processAssert(ConfigAnalytics $configAnalytics) + { + \PHPUnit_Framework_Assert::assertEquals( + true, + $configAnalytics->getAnalyticsForm()->getAnalyticsVerticalScope(), + 'Magento Analytics vertical scope is not website' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Magento Analytics vertical scope is website'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php new file mode 100644 index 0000000000000..de1facb47230b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php @@ -0,0 +1,49 @@ +open(); + $dashboard->getSubscriptionBlock()->enableCheckbox(); + $dashboard->getSubscriptionBlock()->declineAdvancedReporting(); + $dashboard->getModalBlock()->dismissWarning(); + $dashboard->getSubscriptionBlock()->declineAdvancedReporting(); + \PHPUnit_Framework_Assert::assertFalse( + $dashboard->getSubscriptionBlock()->isVisible(), + 'Advanced Reporting was not disabled' + ); + $dashboard->getModalBlock()->acceptWarning(); + \PHPUnit_Framework_Assert::assertFalse( + $dashboard->getModalBlock()->isVisible(), + 'Advanced Reporting disabling was not confirmed' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Advanced Reporting was disabled'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php new file mode 100644 index 0000000000000..3cf503047e6ea --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php @@ -0,0 +1,42 @@ + Configuration > General > Analytics > General menu. + */ +class AssertEmptyVerticalCanNotBeSaved extends AbstractConstraint +{ + /** + * Assert Analytics empty Vertical can not be saved in Stores > Configuration > General > Analytics > General menu. + * + * @param ConfigAnalytics $configAnalytics + * @param string $errorMessage + * @return void + */ + public function processAssert(ConfigAnalytics $configAnalytics, $errorMessage) + { + \PHPUnit_Framework_Assert::assertEquals( + $errorMessage, + $configAnalytics->getMessages()->getErrorMessage(), + 'There is no error message when saving empty vertical in configuration' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return + 'Empty Magento Analytics vertical can not be saved'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php new file mode 100644 index 0000000000000..9205ee89f0913 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php @@ -0,0 +1,42 @@ +open(); + $dashboard->getSubscriptionBlock()->enableCheckbox(); + $dashboard->getSubscriptionBlock()->acceptAdvancedReporting(); + \PHPUnit_Framework_Assert::assertFalse( + $dashboard->getSubscriptionBlock()->isVisible(), + 'Advanced Reporting was not enabled' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Advanced Reporting was enabled'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php new file mode 100644 index 0000000000000..ddb3593537ad8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php @@ -0,0 +1,42 @@ +open(); + $dashboard->getSubscriptionBlock()->disableCheckbox(); + $dashboard->getSubscriptionBlock()->skipAdvancedReporting(); + \PHPUnit_Framework_Assert::assertFalse( + $dashboard->getSubscriptionBlock()->isVisible(), + 'Advanced Reporting was not skipped' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Advanced Reporting was skipped'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php new file mode 100644 index 0000000000000..c2bb48f4bb2ec --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php @@ -0,0 +1,39 @@ +getSubscriptionBlock()->isVisible(), + "Subscription form is visible on dashboard." + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return "Subscription form is absent on dashboard."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php new file mode 100644 index 0000000000000..514c83a30ff51 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php @@ -0,0 +1,42 @@ + Configuration > General > Analytics > General menu. + */ +class AssertVerticalIsSet extends AbstractConstraint +{ + /** + * Assert Analytics Vertical is set in Stores > Configuration > General > Analytics > General menu. + * + * @param ConfigAnalytics $configAnalytics + * @param string $vertical + * @return void + */ + public function processAssert(ConfigAnalytics $configAnalytics, $vertical) + { + \PHPUnit_Framework_Assert::assertEquals( + $vertical, + $configAnalytics->getAnalyticsForm()->getAnalyticsVertical(), + $vertical . 'vertical is not selected' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return + 'Proper Magento Analytics vertical is selected'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/ConfigAnalytics.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/ConfigAnalytics.xml new file mode 100644 index 0000000000000..d4a96e588261f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/ConfigAnalytics.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml new file mode 100644 index 0000000000000..bc94ef7862ca7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/DefaultTimeZone.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/DefaultTimeZone.xml new file mode 100644 index 0000000000000..80d142f8abd60 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/DefaultTimeZone.xml @@ -0,0 +1,35 @@ + + + + + + + 0 + Timezone + Europe/Kiev + + + 0 + Time of day to send data + 01,00,00 + + + + + 0 + Timezone + UTC + + + 0 + Time of day to send data + 02,00,00 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Integration.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Integration.xml new file mode 100644 index 0000000000000..0b4f80512f197 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Integration.xml @@ -0,0 +1,16 @@ + + + + + + + Analytics + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml new file mode 100644 index 0000000000000..6d067a691d59d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml @@ -0,0 +1,19 @@ + + + + + + RoleName%isolation% + Custom + %current_password% + + Magento_Backend::dashboard + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/User.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/User.xml new file mode 100644 index 0000000000000..13bbb4d1306c5 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/User.xml @@ -0,0 +1,24 @@ + + + + + + AdminUser%isolation% + FirstName%isolation% + LastName%isolation% + email%isolation%@example.com + 123123q + 123123q + + role::role_without_subscription_permissions + + %current_password% + Active + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.php new file mode 100644 index 0000000000000..970ce59ceb5bf --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.php @@ -0,0 +1,36 @@ +open(); + $dashboard->getReportsSectionBlock()->click(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.xml new file mode 100644 index 0000000000000..a975d19ef8879 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.xml @@ -0,0 +1,15 @@ + + + + + + https://advancedreporting.rjmetrics.com/report + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php new file mode 100644 index 0000000000000..2fe656081d162 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php @@ -0,0 +1,37 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml new file mode 100644 index 0000000000000..f3ed3736e2ea2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml @@ -0,0 +1,15 @@ + + + + + + custom_admin_with_role_without_subscription_permissions + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.php new file mode 100644 index 0000000000000..b52fa92ad6743 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.php @@ -0,0 +1,42 @@ +Configuration>General>Advanced Reporting->General + * 3. Set Option "Advanced Reporting Service" + * 4. Click "Save Config" + * 5. Perform assertions + * + * @ZephyrId MAGETWO-66465 + */ +class EnableDisableTest extends Injectable +{ + /* tags */ + const MVP = 'no'; + const SEVERITY = 'S1'; + /* end tags */ + + /** + * @param ConfigAnalytics $configAnalytics + * @param string $vertical + * @param string $state + * @return void + */ + public function test(ConfigAnalytics $configAnalytics, $vertical, $state) + { + $configAnalytics->open(); + $configAnalytics->getAnalyticsForm()->analyticsToggle($state); + $configAnalytics->getAnalyticsForm()->setAnalyticsVertical($vertical); + $configAnalytics->getAnalyticsForm()->saveConfig(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.xml new file mode 100644 index 0000000000000..fdc92ed814a90 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.xml @@ -0,0 +1,21 @@ + + + + + + Apps and Games + Disable + + + + Apps and Games + Enable + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml new file mode 100644 index 0000000000000..8e19e1116da19 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml @@ -0,0 +1,28 @@ + + + + + + severity:S1 + Apps and Games + + + + + + severity:S1 + + + + + severity:S1 + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NavigateMenuTest.xml new file mode 100644 index 0000000000000..9c19f80e91d39 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NavigateMenuTest.xml @@ -0,0 +1,23 @@ + + + + + + Reports > BI Essentials + false + https://dashboard.rjmetrics.com/v2/magento/signup + + + + Reports > Advanced Reporting + false + https://advancedreporting.rjmetrics.com/report + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.php new file mode 100644 index 0000000000000..e05804c2bfcfb --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.php @@ -0,0 +1,75 @@ +Configuration>General>Advanced Reporting->General + * 3. Set Option "Time of day to send data" + * 4. Click "Save Config" + * 5. Perform assertions + * + * @ZephyrId MAGETWO-66464 + */ +class SetTimeToSendDataTest extends Injectable +{ + /* tags */ + const MVP = 'no'; + const SEVERITY = 'S1'; + /* end tags */ + + /** + * @var array + */ + private $configData; + + /** + * @param ConfigAnalytics $configAnalytics + * @param TestStepFactory $testStepFactory + * @param string $hh + * @param string $mm + * @param string $vertical + * @param string $configData + * @return void + */ + public function test( + ConfigAnalytics $configAnalytics, + TestStepFactory $testStepFactory, + $hh, + $mm, + $vertical, + $configData + ) { + $this->configData = $configData; + $testStepFactory->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData] + )->run(); + + $configAnalytics->open(); + $configAnalytics->getAnalyticsForm()->setAnalyticsVertical($vertical); + $configAnalytics->getAnalyticsForm()->setTimeOfDayToSendData($hh, $mm); + $configAnalytics->getAnalyticsForm()->saveConfig(); + } + + /** + * Clean data after running test. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData, 'rollback' => true] + )->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.xml new file mode 100644 index 0000000000000..21cc1f732c1f8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.xml @@ -0,0 +1,18 @@ + + + + + + Apps and Games + 11 + 11 + change_default_timezone + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php new file mode 100644 index 0000000000000..a721774f4d22c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php @@ -0,0 +1,40 @@ +open(); + $configAnalytics->getAnalyticsForm()->setAnalyticsVertical($vertical); + $configAnalytics->getAnalyticsForm()->saveConfig(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml new file mode 100644 index 0000000000000..1db31781ccc2f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml @@ -0,0 +1,21 @@ + + + + + + Apps and Games + + + + + --Please Select-- + Please select a vertical. + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/OpenAnalyticsConfigStep.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/OpenAnalyticsConfigStep.php new file mode 100644 index 0000000000000..1f0a8ff4804a3 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/OpenAnalyticsConfigStep.php @@ -0,0 +1,54 @@ +Configuration->General->Analytics->General menu. + */ +class OpenAnalyticsConfigStep implements TestStepInterface +{ + /** + * Dashboard page. + * + * @var Dashboard + */ + private $dashboard; + + /** + * System Config page. + * + * @var SystemConfigEdit + */ + private $systemConfigPage; + + /** + * @param Dashboard $dashboard + * @param SystemConfigEdit $systemConfigPage + */ + public function __construct(Dashboard $dashboard, SystemConfigEdit $systemConfigPage) + { + $this->dashboard = $dashboard; + $this->systemConfigPage = $systemConfigPage; + } + + /** + * Navigate to Stores->Configuration->General->Analytics->General menu. + * + * @return void + */ + public function run() + { + $this->dashboard->open(); + $this->dashboard->getMenuBlock()->navigate('Stores > Configuration'); + $this->systemConfigPage->getForm()->getGroup('analytics', 'general'); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml new file mode 100644 index 0000000000000..74b10cca43c1f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml @@ -0,0 +1,51 @@ + + + + + + + Magento\Analytics\Mtf\App\State\NotificationTimeHandler + + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S1 + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml new file mode 100644 index 0000000000000..2de77423c0a74 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php index 04ac3eee83245..395fa4cd4d81f 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php @@ -31,18 +31,31 @@ class UpgradeSystemTest extends Injectable protected $adminDashboard; /** - * Injection data. - * + * @var \Magento\Analytics\Mtf\App\State\NotificationTimeHandler + */ + private $analyticsNotificationHandler; + + /** + * @var \Magento\Mtf\Util\Iterator\ApplicationState + */ + private $applicationStateIterator; + + /** * @param Dashboard $adminDashboard * @param SetupWizard $setupWizard - * @return void + * @param \Magento\Analytics\Mtf\App\State\NotificationTimeHandler $analyticsNotificationHandler + * @param \Magento\Mtf\Util\Iterator\ApplicationState $applicationStateIterator */ public function __inject( Dashboard $adminDashboard, - SetupWizard $setupWizard + SetupWizard $setupWizard, + \Magento\Analytics\Mtf\App\State\NotificationTimeHandler $analyticsNotificationHandler, + \Magento\Mtf\Util\Iterator\ApplicationState $applicationStateIterator ) { $this->adminDashboard = $adminDashboard; $this->setupWizard = $setupWizard; + $this->analyticsNotificationHandler = $analyticsNotificationHandler; + $this->applicationStateIterator = $applicationStateIterator; } /** @@ -128,6 +141,11 @@ public function test( $assertSuccessMessage->processAssert($this->setupWizard, $upgrade['package']); + // Disable promotion popup for Analytics module + $appStateMetadata = $this->applicationStateIterator->current(); + $appState = \Magento\Mtf\ObjectManager::getInstance()->get($appStateMetadata['class']); + $this->analyticsNotificationHandler->execute($appState); + // Check application version $this->adminDashboard->open(); $assertApplicationVersion->processAssert($this->adminDashboard, $version); diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_1.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_1.xml index 716a6dd89a61f..7fd5c9cb5eda8 100644 --- a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_1.xml +++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_1.xml @@ -11,6 +11,7 @@ + diff --git a/dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php b/dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php new file mode 100644 index 0000000000000..4578286a5d071 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php @@ -0,0 +1,177 @@ +otpResponseResolver = $objectManager->get( + 'OtpResponseResolver' + ); + $this->updateResponseResolver = $objectManager->get( + 'UpdateResponseResolver' + ); + $this->notifyDataChangedResponseResolver = $objectManager->get( + 'NotifyDataChangedResponseResolver' + ); + $this->converter = $objectManager->get(ConverterInterface::class); + $this->flagManager = $objectManager->get(FlagManager::class); + } + + /** + * @magentoDataFixture Magento/Analytics/_files/enabled_subscription_with_invalid_token.php + * @magentoDbIsolation enabled + */ + public function testReSignUpOnOtp() + { + $body = $this->converter->toBody(['test' => '42']); + $retryResponse = new \Zend_Http_Response(401, [$this->converter->getContentTypeHeader()], $body); + $this->otpResponseResolver->getResult($retryResponse); + $this->assertCronWasSet(); + } + + /** + * @magentoDataFixture Magento/Analytics/_files/enabled_subscription_with_invalid_token.php + * @magentoDbIsolation enabled + */ + public function testReSignOnOtpWasNotCalled() + { + $body = $this->converter->toBody(['test' => '42']); + $successResponse = new \Zend_Http_Response(201, [$this->converter->getContentTypeHeader()], $body); + $this->otpResponseResolver->getResult($successResponse); + $this->assertCronWasNotSet(); + } + + /** + * @magentoDataFixture Magento/Analytics/_files/enabled_subscription_with_invalid_token.php + * @magentoDbIsolation enabled + */ + public function testReSignUpOnUpdateWasCalled() + { + $body = $this->converter->toBody(['test' => '42']); + $retryResponse = new \Zend_Http_Response(401, [$this->converter->getContentTypeHeader()], $body); + $this->updateResponseResolver->getResult($retryResponse); + $this->assertCronWasSet(); + } + + /** + * @magentoDataFixture Magento/Analytics/_files/enabled_subscription_with_invalid_token.php + * @magentoDbIsolation enabled + */ + public function testReSignUpOnUpdateWasNotCalled() + { + $body = $this->converter->toBody(['test' => '42']); + $successResponse = new \Zend_Http_Response(201, [$this->converter->getContentTypeHeader()], $body); + $this->updateResponseResolver->getResult($successResponse); + $this->assertCronWasNotSet(); + } + + /** + * @magentoDataFixture Magento/Analytics/_files/enabled_subscription_with_invalid_token.php + * @magentoDbIsolation enabled + */ + public function testReSignUpOnNotifyDataChangedWasNotCalledWhenSubscriptionUpdateIsRunning() + { + $this->flagManager + ->saveFlag( + SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, + 'https://previous.example.com/' + ); + $body = $this->converter->toBody(['test' => '42']); + $retryResponse = new \Zend_Http_Response(401, [$this->converter->getContentTypeHeader()], $body); + $this->notifyDataChangedResponseResolver->getResult($retryResponse); + $this->assertCronWasNotSet(); + } + + /** + * @return string|null + */ + private function getSubscribeSchedule() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** + * @var $scopeConfig ScopeConfigInterface + */ + $scopeConfig = $objectManager->get(ScopeConfigInterface::class); + + return $scopeConfig->getValue( + SubscriptionHandler::CRON_STRING_PATH, + ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + 0 + ); + } + + /** + * @return int|null + */ + private function getAttemptFlag() + { + $objectManager = Bootstrap::getObjectManager(); + /** + * @var $flagManager FlagManager + */ + $flagManager = $objectManager->get(FlagManager::class); + + return $flagManager->getFlagData(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + } + + /** + * @return void + */ + private function assertCronWasSet() + { + $this->assertEquals('0 * * * *', $this->getSubscribeSchedule()); + $this->assertGreaterThan(1, $this->getAttemptFlag()); + } + + /** + * @return void + */ + private function assertCronWasNotSet() + { + $this->assertNull($this->getSubscribeSchedule()); + $this->assertNull($this->getAttemptFlag()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php b/dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php new file mode 100644 index 0000000000000..6082712cfabff --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php @@ -0,0 +1,207 @@ +objectManager = Bootstrap::getObjectManager(); + $this->preparedValueFactory = $this->objectManager->get(PreparedValueFactory::class); + $this->configValueResourceModel = $this->objectManager->get(ConfigData::class); + $this->scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $this->flagManager = $this->objectManager->get(FlagManager::class); + } + + /** + * @magentoDbIsolation enabled + */ + public function testAfterSaveNotSecureUrl() + { + $this->saveConfigValue( + Store::XML_PATH_UNSECURE_BASE_URL, + 'http://store.com/', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + $this->assertCronWasNotSet(); + } + + /** + * @magentoDbIsolation enabled + */ + public function testAfterSaveSecureUrlNotInDefaultScope() + { + $this->saveConfigValue( + Store::XML_PATH_SECURE_BASE_URL, + 'https://store.com/', + ScopeInterface::SCOPE_STORES + ); + $this->assertCronWasNotSet(); + } + + /** + * @magentoDbIsolation enabled + * @magentoAdminConfigFixture web/secure/base_url https://previous.example.com/ + */ + public function testAfterSaveSecureUrlInDefaultScopeOnDoesNotRegisteredInstance() + { + $this->saveConfigValue( + Store::XML_PATH_SECURE_BASE_URL, + 'https://store.com/', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + $this->assertCronWasNotSet(); + } + + /** + * @magentoDbIsolation enabled + * @magentoAdminConfigFixture web/secure/base_url https://previous.example.com/ + * @magentoAdminConfigFixture analytics/general/token MBI_token + */ + public function testAfterSaveSecureUrlInDefaultScopeOnRegisteredInstance() + { + $this->saveConfigValue( + Store::XML_PATH_SECURE_BASE_URL, + 'https://store.com/', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + $this->assertCronWasSet(); + } + + /** + * @magentoDbIsolation enabled + * @magentoAdminConfigFixture web/secure/base_url https://previous.example.com/ + * @magentoAdminConfigFixture analytics/general/token MBI_token + */ + public function testAfterSaveMultipleBaseUrlChanges() + { + $this->saveConfigValue( + Store::XML_PATH_SECURE_BASE_URL, + 'https://store.com/', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + + $this->saveConfigValue( + Store::XML_PATH_SECURE_BASE_URL, + 'https://store10.com/', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + $this->assertCronWasSet(); + } + + /** + * @param string $path The configuration path in format section/group/field_name + * @param string $value The configuration value + * @param string $scope The configuration scope (default, website, or store) + * @return void + */ + private function saveConfigValue(string $path, string $value, string $scope) + { + $value = $this->preparedValueFactory->create( + $path, + $value, + $scope + ); + $this->configValueResourceModel->save($value); + } + + /** + * @return void + */ + private function assertCronWasNotSet() + { + $this->assertNull($this->getSubscriptionUpdateSchedule()); + $this->assertNull($this->getPreviousUpdateUrl()); + $this->assertNull($this->getUpdateReverseCounter()); + } + + /** + * @return void + */ + private function assertCronWasSet() + { + $this->assertSame( + '0 * * * *', + $this->getSubscriptionUpdateSchedule(), + 'Subscription update schedule has not been set' + ); + $this->assertSame( + 'https://previous.example.com/', + $this->getPreviousUpdateUrl(), + 'The previous URL stored for update is not correct' + ); + $this->assertSame(48, $this->getUpdateReverseCounter()); + } + + /** + * @return mixed + */ + private function getSubscriptionUpdateSchedule() + { + return $this->scopeConfig->getValue( + SubscriptionUpdateHandler::UPDATE_CRON_STRING_PATH, + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + } + + /** + * @return mixed + */ + private function getPreviousUpdateUrl() + { + return $this->flagManager->getFlagData(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE); + } + + /** + * @return mixed + */ + private function getUpdateReverseCounter() + { + return $this->flagManager + ->getFlagData(SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php b/dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php new file mode 100644 index 0000000000000..97d9b7cab0675 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php @@ -0,0 +1,56 @@ +reportUrlProvider = $objectManager->get(ReportUrlProvider::class); + $this->flagManager = $objectManager->get(FlagManager::class); + } + + /** + * @magentoDbIsolation enabled + */ + public function testGetUrlWhenSubscriptionUpdateIsRunning() + { + $this->flagManager + ->saveFlag( + SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, + 'https://previous.example.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/dev/tests/integration/testsuite/Magento/Analytics/_files/create_link.php b/dev/tests/integration/testsuite/Magento/Analytics/_files/create_link.php new file mode 100644 index 0000000000000..928bb6fb36a06 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Analytics/_files/create_link.php @@ -0,0 +1,21 @@ +create(\Magento\Analytics\Model\FileInfoManager::class); + +/** + * @var $fileInfo \Magento\Analytics\Model\FileInfo + */ +$fileInfo = $objectManager->create( + \Magento\Analytics\Model\FileInfo::class, + ['path' => 'analytics/jsldjsfdkldf/data.tgz', 'initializationVector' => 'binaryDataisdodssds8iui'] +); + +$fileInfoManager->save($fileInfo); diff --git a/dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token.php b/dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token.php new file mode 100644 index 0000000000000..0106bf6f1bdac --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token.php @@ -0,0 +1,29 @@ +get(\Magento\Framework\App\Config\Storage\WriterInterface::class); + +$configWriter->delete(SubscriptionHandler::CRON_STRING_PATH); +$configWriter->save('analytics/subscription/enabled', 1); + +/** + * @var $analyticsToken \Magento\Analytics\Model\AnalyticsToken + */ +$analyticsToken = $objectManager->get(\Magento\Analytics\Model\AnalyticsToken::class); +$analyticsToken->storeToken('42'); + +/** + * @var $flagManager \Magento\Framework\FlagManager + */ +$flagManager = $objectManager->get(\Magento\Framework\FlagManager::class); + +$flagManager->deleteFlag(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); diff --git a/dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token_rollback.php b/dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token_rollback.php new file mode 100644 index 0000000000000..3fd3e21e282e0 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token_rollback.php @@ -0,0 +1,29 @@ +get(\Magento\Framework\App\Config\Storage\WriterInterface::class); + +$configWriter->delete(SubscriptionHandler::CRON_STRING_PATH); +$configWriter->save('analytics/subscription/enabled', 0); + +/** + * @var $analyticsToken \Magento\Analytics\Model\AnalyticsToken + */ +$analyticsToken = $objectManager->get(\Magento\Analytics\Model\AnalyticsToken::class); +$analyticsToken->storeToken(null); + +/** + * @var $flagManager \Magento\Framework\FlagManager + */ +$flagManager = $objectManager->get(\Magento\Framework\FlagManager::class); + +$flagManager->deleteFlag(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js new file mode 100644 index 0000000000000..9f691c8dc2d05 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js @@ -0,0 +1,126 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +/* global jQuery */ +/* eslint-disable max-nested-callbacks */ +define([ + 'jquery', + 'squire' +], function ($, Squire) { + 'use strict'; + + var injector = new Squire(), + mocks = { + 'Magento_Ui/js/modal/alert': jasmine.createSpy(), + 'uiRegistry': jasmine.createSpy() + }, + obj; + + describe('Magento_Analytics/js/modal/modal-component', function () { + beforeEach(function (done) { + injector.mock(mocks); + injector.require(['Magento_Analytics/js/modal/modal-component'], function (Constr) { + obj = new Constr({ + provider: 'provName', + name: '', + index: '', + links: '', + listens: '', + + /** + * @return {Object} source - mock for form data + */ + form: function () { + return { + source: { + data: {} + } + }; + } + }); + done(); + }); + }); + describe('"sendPostponeRequest" method', function () { + it('should send a ajax request', function () { + jQuery.ajax = jasmine.createSpy().and.callFake(function () { + var d = $.Deferred(); + + d.resolve({ + 'success': true + }); + + return d.promise(); + }); + + obj.sendPostponeRequest({}); + + expect(jQuery.ajax).toHaveBeenCalled(); + }); + + it('should call "onError" method if ajax received error', function () { + spyOn(obj, 'onError'); + jQuery.ajax = jasmine.createSpy().and.callFake(function () { + var d = $.Deferred(); + + d.resolve({ + 'error': true + }); + + return d.promise(); + }); + + obj.sendPostponeRequest({}); + + expect(jQuery.ajax).toHaveBeenCalled(); + expect(obj.onError).toHaveBeenCalled(); + }); + + it('should call "onError" method if request failed', function () { + spyOn(obj, 'onError'); + jQuery.ajax = jasmine.createSpy().and.callFake(function () { + var d = $.Deferred(); + + d.reject(); + + return d.promise(); + }); + + obj.sendPostponeRequest({}); + + expect(jQuery.ajax).toHaveBeenCalled(); + expect(obj.onError).toHaveBeenCalled(); + }); + }); + + describe('"onError" method', function () { + var abortRequest = { + statusText: 'abort' + }, + errorRequest = { + error: true, + message: 'Error text' + }; + + it('should do nothing if request aborted', function () { + expect(obj.onError(abortRequest)).toBeUndefined(); + }); + + it('should show alert with error', function () { + obj.onError(errorRequest); + expect(mocks['Magento_Ui/js/modal/alert']).toHaveBeenCalled(); + }); + }); + + describe('"actionCancel" method', function () { + it('should call "sendPostponeRequest" and "closeModal" methods', function () { + spyOn(obj, 'sendPostponeRequest'); + spyOn(obj, 'closeModal'); + obj.actionCancel(); + expect(obj.sendPostponeRequest).toHaveBeenCalledWith(obj.postponeOptions); + expect(obj.closeModal).toHaveBeenCalled(); + }); + }); + }); +}); From dc61daa5dfbcb1774f4cf30dcb2c9d5a8bc985f5 Mon Sep 17 00:00:00 2001 From: Joan He Date: Fri, 15 Sep 2017 14:15:20 -0500 Subject: [PATCH 002/194] MAGETWO-80488: Apply AR code from previous development - update tests to PHPUnit version 6 --- .../Adminhtml/System/Config/AdditionalCommentTest.php | 2 +- .../Adminhtml/System/Config/CollectionTimeLabelTest.php | 2 +- .../System/Config/SubscriptionStatusLabelTest.php | 2 +- .../Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php | 2 +- .../Test/Unit/Controller/Adminhtml/Reports/ShowTest.php | 2 +- .../Controller/Adminhtml/Subscription/ActivateTest.php | 2 +- .../Controller/Adminhtml/Subscription/PostponeTest.php | 2 +- .../Unit/Controller/Adminhtml/Subscription/RetryTest.php | 2 +- .../Magento/Analytics/Test/Unit/Cron/CollectDataTest.php | 2 +- app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php | 2 +- app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php | 2 +- .../Analytics/Test/Unit/Model/AnalyticsTokenTest.php | 2 +- .../Test/Unit/Model/Condition/CanViewNotificationTest.php | 2 +- .../Backend/Baseurl/SubscriptionUpdateHandlerTest.php | 2 +- .../Test/Unit/Model/Config/Backend/CollectionTimeTest.php | 2 +- .../Config/Backend/Enabled/SubscriptionHandlerTest.php | 2 +- .../Test/Unit/Model/Config/Backend/EnabledTest.php | 2 +- .../Test/Unit/Model/Config/Backend/VerticalTest.php | 2 +- .../Analytics/Test/Unit/Model/Config/MapperTest.php | 2 +- .../Analytics/Test/Unit/Model/Config/ReaderTest.php | 2 +- .../Test/Unit/Model/Config/Source/VerticalTest.php | 2 +- app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php | 2 +- .../Test/Unit/Model/Connector/Http/Client/CurlTest.php | 2 +- .../Test/Unit/Model/Connector/Http/JsonConverterTest.php | 2 +- .../Unit/Model/Connector/Http/ResponseResolverTest.php | 2 +- .../Unit/Model/Connector/NotifyDataChangedCommandTest.php | 2 +- .../Test/Unit/Model/Connector/OTPRequestTest.php | 2 +- .../Test/Unit/Model/Connector/ResponseHandler/OTPTest.php | 2 +- .../Unit/Model/Connector/ResponseHandler/ReSignUpTest.php | 2 +- .../Unit/Model/Connector/ResponseHandler/SignUpTest.php | 2 +- .../Unit/Model/Connector/ResponseHandler/UpdateTest.php | 2 +- .../Test/Unit/Model/Connector/SignUpCommandTest.php | 2 +- .../Test/Unit/Model/Connector/UpdateCommandTest.php | 2 +- .../Magento/Analytics/Test/Unit/Model/ConnectorTest.php | 2 +- .../Analytics/Test/Unit/Model/CryptographerTest.php | 2 +- .../Analytics/Test/Unit/Model/EncodedContextTest.php | 2 +- .../Test/Unit/Model/ExportDataHandlerNotificationTest.php | 2 +- .../Analytics/Test/Unit/Model/ExportDataHandlerTest.php | 2 +- .../Analytics/Test/Unit/Model/FileInfoManagerTest.php | 2 +- .../Magento/Analytics/Test/Unit/Model/FileInfoTest.php | 2 +- .../Analytics/Test/Unit/Model/FileRecorderTest.php | 2 +- .../Analytics/Test/Unit/Model/IntegrationManagerTest.php | 2 +- .../Analytics/Test/Unit/Model/LinkProviderTest.php | 2 +- .../Analytics/Test/Unit/Model/NotificationTimeTest.php | 2 +- .../Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php | 2 +- .../Analytics/Test/Unit/Model/ReportUrlProviderTest.php | 8 ++------ .../Analytics/Test/Unit/Model/ReportWriterTest.php | 2 +- .../Test/Unit/Model/ReportXml/ModuleIteratorTest.php | 2 +- .../Test/Unit/Model/StoreConfigurationProviderTest.php | 2 +- .../Test/Unit/Model/SubscriptionStatusProviderTest.php | 2 +- .../Message/NotificationAboutFailedSubscriptionTest.php | 2 +- .../Test/Unit/ReportXml/Config/Converter/XmlTest.php | 2 +- .../Analytics/Test/Unit/ReportXml/Config/MapperTest.php | 2 +- .../Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php | 2 +- .../Test/Unit/ReportXml/ConnectionFactoryTest.php | 2 +- .../Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php | 2 +- .../Unit/ReportXml/DB/Assembler/FromAssemblerTest.php | 2 +- .../Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php | 2 +- .../Test/Unit/ReportXml/DB/ColumnsResolverTest.php | 2 +- .../Test/Unit/ReportXml/DB/ConditionResolverTest.php | 2 +- .../Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php | 2 +- .../Test/Unit/ReportXml/DB/ReportValidatorTest.php | 2 +- .../Test/Unit/ReportXml/DB/SelectBuilderTest.php | 2 +- .../Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php | 2 +- .../Analytics/Test/Unit/ReportXml/QueryFactoryTest.php | 2 +- .../Magento/Analytics/Test/Unit/ReportXml/QueryTest.php | 2 +- .../Analytics/Test/Unit/ReportXml/ReportProviderTest.php | 2 +- .../Analytics/Test/Unit/ReportXml/SelectHydratorTest.php | 2 +- .../Test/Unit/Ui/DataProvider/DummyDataProviderTest.php | 2 +- .../Model/Connector/Http/ReSignUpResponseResolverTest.php | 2 +- .../Analytics/Model/Plugin/BaseUrlConfigPluginTest.php | 2 +- .../Magento/Analytics/Model/ReportUrlProviderTest.php | 8 ++------ 72 files changed, 74 insertions(+), 82 deletions(-) diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php index b94a295c86527..744ba7466e593 100644 --- a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php @@ -10,7 +10,7 @@ use Magento\Framework\Data\Form; use Magento\Framework\Data\Form\Element\AbstractElement; -class AdditionalCommentTest extends \PHPUnit_Framework_TestCase +class AdditionalCommentTest extends \PHPUnit\Framework\TestCase { /** * @var AdditionalComment diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php index d37daf9525119..74fbbf2e78a40 100644 --- a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php @@ -11,7 +11,7 @@ use Magento\Framework\Data\Form\Element\AbstractElement; use Magento\Framework\Stdlib\DateTime\TimezoneInterface; -class CollectionTimeLabelTest extends \PHPUnit_Framework_TestCase +class CollectionTimeLabelTest extends \PHPUnit\Framework\TestCase { /** * @var CollectionTimeLabel diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php index e25e745317699..04728c403a861 100644 --- a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php @@ -14,7 +14,7 @@ /** * Class SignupTest */ -class SubscriptionStatusLabelTest extends \PHPUnit_Framework_TestCase +class SubscriptionStatusLabelTest extends \PHPUnit\Framework\TestCase { /** * @var SubscriptionStatusLabel diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php index 3a251f9a8685a..6f613cdc4d639 100644 --- a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php @@ -14,7 +14,7 @@ /** * Class SignupTest */ -class SignUpTest extends \PHPUnit_Framework_TestCase +class SignUpTest extends \PHPUnit\Framework\TestCase { /** * @var ObjectManagerHelper 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 99de92cc63905..4f54ce5059965 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 @@ -17,7 +17,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class ShowTest extends \PHPUnit_Framework_TestCase +class ShowTest extends \PHPUnit\Framework\TestCase { /** * @var ReportUrlProvider|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php index 9097349e9137c..66c7ae4fac448 100644 --- a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php @@ -20,7 +20,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class ActivateTest extends \PHPUnit_Framework_TestCase +class ActivateTest extends \PHPUnit\Framework\TestCase { /** * @var ResultFactory|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php index 0f425291bf999..1fb7126146767 100644 --- a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php @@ -19,7 +19,7 @@ /** * Class PostponeTest */ -class PostponeTest extends \PHPUnit_Framework_TestCase +class PostponeTest extends \PHPUnit\Framework\TestCase { /** * @var \PHPUnit_Framework_MockObject_MockObject|DateTimeFactory diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php index 2c921e2260140..17c485a8df230 100644 --- a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php @@ -18,7 +18,7 @@ /** * Class RetryTest */ -class RetryTest extends \PHPUnit_Framework_TestCase +class RetryTest extends \PHPUnit\Framework\TestCase { /** * @var ResultFactory|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php b/app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php index ef071cdf3a911..81c57d79033c8 100644 --- a/app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php @@ -13,7 +13,7 @@ /** * Class CollectDataTest */ -class CollectDataTest extends \PHPUnit_Framework_TestCase +class CollectDataTest extends \PHPUnit\Framework\TestCase { /** * @var ExportDataHandlerInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php index c8ab5a6f4649e..959a11f9e1058 100644 --- a/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php @@ -15,7 +15,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class SignUpTest extends \PHPUnit_Framework_TestCase +class SignUpTest extends \PHPUnit\Framework\TestCase { /** * @var Connector|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php b/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php index 23ba59a90ce7b..ede53d8783a7a 100644 --- a/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php @@ -16,7 +16,7 @@ /** * Class Update */ -class UpdateTest extends \PHPUnit_Framework_TestCase +class UpdateTest extends \PHPUnit\Framework\TestCase { /** * @var Connector|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php index e078bbe99f93a..57315543bc32d 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php @@ -14,7 +14,7 @@ /** * Class AnalyticsTokenTest */ -class AnalyticsTokenTest extends \PHPUnit_Framework_TestCase +class AnalyticsTokenTest extends \PHPUnit\Framework\TestCase { /** * @var ReinitableConfigInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index bfdc971efc79e..755db7e0b3ab1 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -14,7 +14,7 @@ /** * Class CanViewNotificationTest */ -class CanViewNotificationTest extends \PHPUnit_Framework_TestCase +class CanViewNotificationTest extends \PHPUnit\Framework\TestCase { /** * @var NotificationTime|\PHPUnit_Framework_MockObject_MockObject 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 index 865ad236fc057..f5f721c038c57 100644 --- 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 @@ -13,7 +13,7 @@ use Magento\Framework\FlagManager; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -class SubscriptionUpdateHandlerTest extends \PHPUnit_Framework_TestCase +class SubscriptionUpdateHandlerTest extends \PHPUnit\Framework\TestCase { /** * @var AnalyticsToken|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/CollectionTimeTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/CollectionTimeTest.php index 555020ffd247f..071b96111ac8b 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/CollectionTimeTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/CollectionTimeTest.php @@ -14,7 +14,7 @@ /** * Class CollectionTimeTest */ -class CollectionTimeTest extends \PHPUnit_Framework_TestCase +class CollectionTimeTest extends \PHPUnit\Framework\TestCase { /** * @var WriterInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php index d01101bf5cc3b..e5ec3f80322a9 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php @@ -17,7 +17,7 @@ /** * Class SubscriptionHandlerTest */ -class SubscriptionHandlerTest extends \PHPUnit_Framework_TestCase +class SubscriptionHandlerTest extends \PHPUnit\Framework\TestCase { /** * @var FlagManager|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php index d64827d2d18d2..eea3193258bc6 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php @@ -16,7 +16,7 @@ /** * Class EnabledTest */ -class EnabledTest extends \PHPUnit_Framework_TestCase +class EnabledTest extends \PHPUnit\Framework\TestCase { /** * @var SubscriptionHandler|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php index d689f040c48b3..6fe7d0aa93998 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php @@ -8,7 +8,7 @@ /** * A unit test for testing of the backend model for verticals configuration. */ -class VerticalTest extends \PHPUnit_Framework_TestCase +class VerticalTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\Model\Config\Backend\Vertical diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php index 7c94fb1b60a14..0b7f4870dbac8 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php @@ -11,7 +11,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class MapperTest extends \PHPUnit_Framework_TestCase +class MapperTest extends \PHPUnit\Framework\TestCase { /** * @var ObjectManagerHelper diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php index 1eee74a1f93a0..6aa9c7ef3106c 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php @@ -13,7 +13,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class ReaderTest extends \PHPUnit_Framework_TestCase +class ReaderTest extends \PHPUnit\Framework\TestCase { /** * @var Mapper|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php index b96f3543ff701..c13205d34f25b 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php @@ -8,7 +8,7 @@ /** * A unit test for testing of the source model for verticals configuration. */ -class VerticalTest extends \PHPUnit_Framework_TestCase +class VerticalTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\Model\Config\Source\Vertical diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php index 8282b1ae52617..8739219ebdf09 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php @@ -12,7 +12,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class ConfigTest extends \PHPUnit_Framework_TestCase +class ConfigTest extends \PHPUnit\Framework\TestCase { /** * @var DataInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php index 6890fe200f9dc..f8f3919b2489e 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php @@ -12,7 +12,7 @@ /** * A unit test for testing of the CURL HTTP client. */ -class CurlTest extends \PHPUnit_Framework_TestCase +class CurlTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\Model\Connector\Http\Client\Curl diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php index 7ac6f50ea24c4..60a19f3d5079e 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php @@ -10,7 +10,7 @@ /** * Class JsonConverterTest */ -class JsonConverterTest extends \PHPUnit_Framework_TestCase +class JsonConverterTest extends \PHPUnit\Framework\TestCase { public function testConverterContainsHeader() { diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php index 5047e8a9dd391..7c3c484843285 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php @@ -12,7 +12,7 @@ /** * Class ResponseResolverTest */ -class ResponseResolverTest extends \PHPUnit_Framework_TestCase +class ResponseResolverTest extends \PHPUnit\Framework\TestCase { public function testGetResultHandleResponseSuccess() { 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 5b86dd6557d69..cee3877631c2e 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php @@ -14,7 +14,7 @@ use Magento\Analytics\Model\Connector\NotifyDataChangedCommand; use Magento\Analytics\Model\Connector\Http\ClientInterface; -class NotifyDataChangedCommandTest extends \PHPUnit_Framework_TestCase +class NotifyDataChangedCommandTest extends \PHPUnit\Framework\TestCase { /** * @var NotifyDataChangedCommand diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php index a33d7d0d7c1bf..8a3f4efb15cf4 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php @@ -15,7 +15,7 @@ /** * A unit test for testing of the representation of a 'OTP' request. */ -class OTPRequestTest extends \PHPUnit_Framework_TestCase +class OTPRequestTest extends \PHPUnit\Framework\TestCase { /** * @var OTPRequest diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php index 203eb57157e0e..0ff36cca5db2d 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php @@ -10,7 +10,7 @@ /** * Class OTPTest */ -class OTPTest extends \PHPUnit_Framework_TestCase +class OTPTest extends \PHPUnit\Framework\TestCase { public function testHandleResult() { diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php index 4c3dde7a92c3f..707003149bcfd 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php @@ -13,7 +13,7 @@ /** * Class ReSignUpTest */ -class ReSignUpTest extends \PHPUnit_Framework_TestCase +class ReSignUpTest extends \PHPUnit\Framework\TestCase { public function testHandleResult() { diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php index 2bbd528638a19..81711cfc56950 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php @@ -12,7 +12,7 @@ /** * Class SignUpTest */ -class SignUpTest extends \PHPUnit_Framework_TestCase +class SignUpTest extends \PHPUnit\Framework\TestCase { public function testHandleResult() { diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php index 90102e2c3d868..7779357e8bea7 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php @@ -10,7 +10,7 @@ /** * Class UpdateTest */ -class UpdateTest extends \PHPUnit_Framework_TestCase +class UpdateTest extends \PHPUnit\Framework\TestCase { public function testHandleResult() { 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 cc9eba99b3d48..5593496a957b7 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php @@ -18,7 +18,7 @@ /** * Class SignUpCommandTest */ -class SignUpCommandTest extends \PHPUnit_Framework_TestCase +class SignUpCommandTest extends \PHPUnit\Framework\TestCase { /** * @var SignUpCommand 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 eb22461d789c8..47253a13530e5 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php @@ -18,7 +18,7 @@ /** * Class SignUpCommandTest */ -class UpdateCommandTest extends \PHPUnit_Framework_TestCase +class UpdateCommandTest extends \PHPUnit\Framework\TestCase { /** * @var UpdateCommand diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php index 14d641a19729d..4414b81cbc183 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php @@ -12,7 +12,7 @@ /** * Class SignUpCommandTest */ -class ConnectorTest extends \PHPUnit_Framework_TestCase +class ConnectorTest extends \PHPUnit\Framework\TestCase { /** * @var ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php index 3de718d843a1d..a896c309b4007 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php @@ -14,7 +14,7 @@ /** * Class CryptographerTest */ -class CryptographerTest extends \PHPUnit_Framework_TestCase +class CryptographerTest extends \PHPUnit\Framework\TestCase { /** * @var AnalyticsToken|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php b/app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php index 283b13212919d..a1a7c54510681 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php @@ -11,7 +11,7 @@ /** * Class EncodedContextTest */ -class EncodedContextTest extends \PHPUnit_Framework_TestCase +class EncodedContextTest extends \PHPUnit\Framework\TestCase { /** * @var ObjectManagerHelper diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php index b3826c232ed0c..1582c241bf45d 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php @@ -13,7 +13,7 @@ /** * Class ExportDataHandlerNotificationTest */ -class ExportDataHandlerNotificationTest extends \PHPUnit_Framework_TestCase +class ExportDataHandlerNotificationTest extends \PHPUnit\Framework\TestCase { /** * @var ObjectManagerHelper diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php index 7c181bea81aab..6ffb61d088567 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php @@ -19,7 +19,7 @@ /** * Class ExportDataHandlerTest */ -class ExportDataHandlerTest extends \PHPUnit_Framework_TestCase +class ExportDataHandlerTest extends \PHPUnit\Framework\TestCase { /** * @var Filesystem|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php index c8c07ae8240c3..da5f6af3ca4e1 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php @@ -14,7 +14,7 @@ /** * Class FileInfoManagerTest */ -class FileInfoManagerTest extends \PHPUnit_Framework_TestCase +class FileInfoManagerTest extends \PHPUnit\Framework\TestCase { /** * @var FlagManager|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php index 73f6ed644721a..43ce833f1f03f 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php @@ -11,7 +11,7 @@ /** * Class FileInfoTest */ -class FileInfoTest extends \PHPUnit_Framework_TestCase +class FileInfoTest extends \PHPUnit\Framework\TestCase { /** * @var ObjectManagerHelper diff --git a/app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php index 68ff00a433fd2..3c9520bdd995b 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php @@ -18,7 +18,7 @@ /** * Class FileRecorderTest */ -class FileRecorderTest extends \PHPUnit_Framework_TestCase +class FileRecorderTest extends \PHPUnit\Framework\TestCase { /** * @var FileInfoManager|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php index 31d5c77ce50b0..3076a22c85be4 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php @@ -16,7 +16,7 @@ /** * Class IntegrationManagerTest */ -class IntegrationManagerTest extends \PHPUnit_Framework_TestCase +class IntegrationManagerTest extends \PHPUnit\Framework\TestCase { /** * @var IntegrationServiceInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php index afda37962a3cb..c7aa2219d1eee 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php @@ -18,7 +18,7 @@ /** * Class LinkProviderTest */ -class LinkProviderTest extends \PHPUnit_Framework_TestCase +class LinkProviderTest extends \PHPUnit\Framework\TestCase { /** * @var ObjectManagerHelper diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php index 03fe7d968a7f5..581cb1171d318 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php @@ -13,7 +13,7 @@ /** * Class NotificationTimeTest */ -class NotificationTimeTest extends \PHPUnit_Framework_TestCase +class NotificationTimeTest extends \PHPUnit\Framework\TestCase { /** * @var FlagManager|\PHPUnit_Framework_MockObject_MockObject 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 38d073a4b4550..a89e06562383b 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php @@ -17,7 +17,7 @@ /** * Class BaseUrlConfigPluginTest */ -class BaseUrlConfigPluginTest extends \PHPUnit_Framework_TestCase +class BaseUrlConfigPluginTest extends \PHPUnit\Framework\TestCase { /** * @var SubscriptionUpdateHandler | \PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php index ee507d88c68db..0607a977e5b68 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php @@ -17,7 +17,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class ReportUrlProviderTest extends \PHPUnit_Framework_TestCase +class ReportUrlProviderTest extends \PHPUnit\Framework\TestCase { /** * @var ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject @@ -143,11 +143,7 @@ public function testGetUrlWhenSubscriptionUpdateRunning() ->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->expectException(SubscriptionUpdateException::class); $this->reportUrlProvider->getUrl(); } } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php index 96ac1143ec5ec..d9b030b84d639 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php @@ -16,7 +16,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class ReportWriterTest extends \PHPUnit_Framework_TestCase +class ReportWriterTest extends \PHPUnit\Framework\TestCase { /** * @var ConfigInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php index 654fad74ef309..f314d77f32b41 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php @@ -10,7 +10,7 @@ use Magento\Framework\Module\Manager as ModuleManager; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -class ModuleIteratorTest extends \PHPUnit_Framework_TestCase +class ModuleIteratorTest extends \PHPUnit\Framework\TestCase { /** * @var ModuleManager|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php index a2f9be1461c15..cc46d175543ad 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php @@ -12,7 +12,7 @@ use Magento\Store\Api\Data\WebsiteInterface; use Magento\Store\Model\StoreManagerInterface; -class StoreConfigurationProviderTest extends \PHPUnit_Framework_TestCase +class StoreConfigurationProviderTest extends \PHPUnit\Framework\TestCase { /** * @var ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php index 2e52a13f90bbf..d6b041ce03178 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php @@ -16,7 +16,7 @@ /** * Class SubscriptionStatusProviderTest. */ -class SubscriptionStatusProviderTest extends \PHPUnit_Framework_TestCase +class SubscriptionStatusProviderTest extends \PHPUnit\Framework\TestCase { /** * @var ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php b/app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php index 536a7dbb5dfe9..ad1d87488d751 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php @@ -13,7 +13,7 @@ /** * Class NotificationAboutFailedSubscriptionTest */ -class NotificationAboutFailedSubscriptionTest extends \PHPUnit_Framework_TestCase +class NotificationAboutFailedSubscriptionTest extends \PHPUnit\Framework\TestCase { /** * @var \PHPUnit_Framework_MockObject_MockObject|SubscriptionStatusProvider diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php index 325d3d4a85c7e..3f1ed9a5cf4c0 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php @@ -8,7 +8,7 @@ /** * A unit test for testing of the reports configuration converter (XML to PHP array). */ -class XmlTest extends \PHPUnit_Framework_TestCase +class XmlTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\ReportXml\Config\Converter\Xml diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php index f69b40118b935..85343b6b301d6 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php @@ -10,7 +10,7 @@ /** * Class MapperTest */ -class MapperTest extends \PHPUnit_Framework_TestCase +class MapperTest extends \PHPUnit\Framework\TestCase { /** * @var Mapper diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php index 1b89a0d3ad671..cbc9aa129d874 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php @@ -12,7 +12,7 @@ /** * Class ConfigTest */ -class ConfigTest extends \PHPUnit_Framework_TestCase +class ConfigTest extends \PHPUnit\Framework\TestCase { /** * @var DataInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php index 330f7f1a6707a..1e4ae9142c13d 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php @@ -15,7 +15,7 @@ /** * Class ConnectionFactoryTest */ -class ConnectionFactoryTest extends \PHPUnit_Framework_TestCase +class ConnectionFactoryTest extends \PHPUnit\Framework\TestCase { /** * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php index 6ebfd1ffa2da6..3b01105a8873b 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php @@ -8,7 +8,7 @@ /** * A unit test for testing of the 'filter' assembler. */ -class FilterAssemblerTest extends \PHPUnit_Framework_TestCase +class FilterAssemblerTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\ReportXml\DB\Assembler\FilterAssembler diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php index cbabac5613a8b..575db94a7b7e1 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php @@ -10,7 +10,7 @@ /** * A unit test for testing of the 'from' assembler. */ -class FromAssemblerTest extends \PHPUnit_Framework_TestCase +class FromAssemblerTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\ReportXml\DB\Assembler\FromAssembler diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php index b913689513ce5..aaafd731552a0 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php @@ -10,7 +10,7 @@ /** * A unit test for testing of the 'join' assembler. */ -class JoinAssemblerTest extends \PHPUnit_Framework_TestCase +class JoinAssemblerTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\ReportXml\DB\Assembler\JoinAssembler diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php index c8ab79625e9c3..bdbe3d1d22c22 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php @@ -16,7 +16,7 @@ /** * Class ColumnsResolverTest */ -class ColumnsResolverTest extends \PHPUnit_Framework_TestCase +class ColumnsResolverTest extends \PHPUnit\Framework\TestCase { /** * @var SelectBuilder|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php index 2a97e109543cf..c8182d068fba5 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php @@ -14,7 +14,7 @@ /** * Class ConditionResolverTest */ -class ConditionResolverTest extends \PHPUnit_Framework_TestCase +class ConditionResolverTest extends \PHPUnit\Framework\TestCase { /** * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php index ef051feda0722..4accd03aef3ea 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php @@ -11,7 +11,7 @@ /** * Class NameResolverTest */ -class NameResolverTest extends \PHPUnit_Framework_TestCase +class NameResolverTest extends \PHPUnit\Framework\TestCase { /** * @var NameResolver|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php index fad0a80856b70..bbb9ca4b511b6 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php @@ -16,7 +16,7 @@ /** * Class ReportValidatorTest */ -class ReportValidatorTest extends \PHPUnit_Framework_TestCase +class ReportValidatorTest extends \PHPUnit\Framework\TestCase { /** * @var ConnectionFactory|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php index fb8f5b4a1ff0e..a82a187cdb3f8 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php @@ -13,7 +13,7 @@ /** * Class SelectBuilderTest */ -class SelectBuilderTest extends \PHPUnit_Framework_TestCase +class SelectBuilderTest extends \PHPUnit\Framework\TestCase { /** * @var SelectBuilder diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php index 38abc3683f81f..1d3f293ed676a 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php @@ -11,7 +11,7 @@ /** * Class IteratorFactoryTest */ -class IteratorFactoryTest extends \PHPUnit_Framework_TestCase +class IteratorFactoryTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php index e358bf00fe37a..9a3805a50f167 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php @@ -8,7 +8,7 @@ /** * A unit test for testing of the query factory. */ -class QueryFactoryTest extends \PHPUnit_Framework_TestCase +class QueryFactoryTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\ReportXml\QueryFactory diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php index e288c668a54f7..a4b08a9ce5e0a 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php @@ -13,7 +13,7 @@ /** * Class QueryTest */ -class QueryTest extends \PHPUnit_Framework_TestCase +class QueryTest extends \PHPUnit\Framework\TestCase { /** * @var Select|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php index 124d5f32078c8..5f329993dd291 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php @@ -8,7 +8,7 @@ /** * A unit test for testing of the reports provider. */ -class ReportProviderTest extends \PHPUnit_Framework_TestCase +class ReportProviderTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\ReportXml\ReportProvider diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php index dce8089a787dc..ce57a1eca3689 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php @@ -16,7 +16,7 @@ /** * Class SelectHydratorTest */ -class SelectHydratorTest extends \PHPUnit_Framework_TestCase +class SelectHydratorTest extends \PHPUnit\Framework\TestCase { /** * @var SelectHydrator diff --git a/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php index 94f6ed1845c40..a58b050a9d928 100644 --- a/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php @@ -16,7 +16,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class DummyDataProviderTest extends \PHPUnit_Framework_TestCase +class DummyDataProviderTest extends \PHPUnit\Framework\TestCase { /** * @var SearchResultInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php b/dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php index 4578286a5d071..91f2455c61d87 100644 --- a/dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php +++ b/dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php @@ -14,7 +14,7 @@ /** * Checks that cron job was set if error handler was set and appropriate http error code was returned. */ -class ReSignUpResponseResolverTest extends \PHPUnit_Framework_TestCase +class ReSignUpResponseResolverTest extends \PHPUnit\Framework\TestCase { /** * @var ResponseResolver diff --git a/dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php b/dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php index 6082712cfabff..b8933cb5ed3d2 100644 --- a/dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php +++ b/dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php @@ -18,7 +18,7 @@ /** * @magentoAppArea adminhtml */ -class BaseUrlConfigPluginTest extends \PHPUnit_Framework_TestCase +class BaseUrlConfigPluginTest extends \PHPUnit\Framework\TestCase { /** * @var PreparedValueFactory diff --git a/dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php b/dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php index 97d9b7cab0675..0e2f8c4cc96a2 100644 --- a/dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php +++ b/dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php @@ -14,7 +14,7 @@ /** * @magentoAppArea adminhtml */ -class ReportUrlProviderTest extends \PHPUnit_Framework_TestCase +class ReportUrlProviderTest extends \PHPUnit\Framework\TestCase { /** * @var ReportUrlProvider @@ -46,11 +46,7 @@ public function testGetUrlWhenSubscriptionUpdateIsRunning() SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, 'https://previous.example.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->expectException(SubscriptionUpdateException::class); $this->reportUrlProvider->getUrl(); } } From cee7a4c3a87ce095c3c2f1530f2f23e272f8c4c5 Mon Sep 17 00:00:00 2001 From: Joan He Date: Mon, 18 Sep 2017 10:00:31 -0500 Subject: [PATCH 003/194] MAGETWO-80488: Apply AR code from previous development - update test to suppress warnings of PHPMD.UnusedFormalParameter --- .../Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php b/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php index 81724e735f269..0ea32df272729 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php @@ -39,6 +39,7 @@ public function __construct( * @param AbstractState $state * @return bool * @throws \Exception + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function execute(AbstractState $state) { From c543259baf3a12d6a3a6c28c77f7142388d5e819 Mon Sep 17 00:00:00 2001 From: Joan He Date: Mon, 18 Sep 2017 10:40:19 -0500 Subject: [PATCH 004/194] MAGETWO-80488: Apply AR code from previous development - update composer.lock file --- composer.lock | 227 +++++++++++++++++++++++++------------------------- 1 file changed, 114 insertions(+), 113 deletions(-) diff --git a/composer.lock b/composer.lock index cd3ddf4d46cd2..2d4f578422dd5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "51eec653c09ff25e77e5f04058539975", + "hash": "9638b9ba14682bca16191207441a0c38", + "content-hash": "97eff12e92f191fc7f80f6e2ff9c278c", "packages": [ { "name": "braintree/braintree_php", @@ -51,7 +52,7 @@ } ], "description": "Braintree PHP Client Library", - "time": "2017-02-16T19:59:04+00:00" + "time": "2017-02-16 19:59:04" }, { "name": "colinmollenhour/cache-backend-file", @@ -87,7 +88,7 @@ ], "description": "The stock Zend_Cache_Backend_File backend has extremely poor performance for cleaning by tags making it become unusable as the number of cached items increases. This backend makes many changes resulting in a huge performance boost, especially for tag cleaning.", "homepage": "https://github.com/colinmollenhour/Cm_Cache_Backend_File", - "time": "2016-05-02T16:24:47+00:00" + "time": "2016-05-02 16:24:47" }, { "name": "colinmollenhour/cache-backend-redis", @@ -123,7 +124,7 @@ ], "description": "Zend_Cache backend using Redis with full support for tags.", "homepage": "https://github.com/colinmollenhour/Cm_Cache_Backend_Redis", - "time": "2017-03-25T04:54:24+00:00" + "time": "2017-03-25 04:54:24" }, { "name": "colinmollenhour/credis", @@ -162,7 +163,7 @@ ], "description": "Credis is a lightweight interface to the Redis key-value store which wraps the phpredis library when available for better performance.", "homepage": "https://github.com/colinmollenhour/credis", - "time": "2015-11-28T01:20:04+00:00" + "time": "2015-11-28 01:20:04" }, { "name": "colinmollenhour/php-redis-session-abstract", @@ -199,7 +200,7 @@ ], "description": "A Redis-based session handler with optimistic locking", "homepage": "https://github.com/colinmollenhour/php-redis-session-abstract", - "time": "2017-04-19T14:21:43+00:00" + "time": "2017-04-19 14:21:43" }, { "name": "composer/ca-bundle", @@ -258,7 +259,7 @@ "ssl", "tls" ], - "time": "2017-09-11T07:24:36+00:00" + "time": "2017-09-11 07:24:36" }, { "name": "composer/composer", @@ -335,7 +336,7 @@ "dependency", "package" ], - "time": "2017-03-10T08:29:45+00:00" + "time": "2017-03-10 08:29:45" }, { "name": "composer/semver", @@ -397,7 +398,7 @@ "validation", "versioning" ], - "time": "2016-08-30T16:08:34+00:00" + "time": "2016-08-30 16:08:34" }, { "name": "composer/spdx-licenses", @@ -458,7 +459,7 @@ "spdx", "validator" ], - "time": "2017-04-03T19:08:52+00:00" + "time": "2017-04-03 19:08:52" }, { "name": "container-interop/container-interop", @@ -489,7 +490,7 @@ ], "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", "homepage": "https://github.com/container-interop/container-interop", - "time": "2017-02-14T19:40:03+00:00" + "time": "2017-02-14 19:40:03" }, { "name": "justinrainbow/json-schema", @@ -556,7 +557,7 @@ "json", "schema" ], - "time": "2017-05-16T21:06:09+00:00" + "time": "2017-05-16 21:06:09" }, { "name": "league/climate", @@ -605,7 +606,7 @@ "php", "terminal" ], - "time": "2015-01-18T14:31:58+00:00" + "time": "2015-01-18 14:31:58" }, { "name": "magento/composer", @@ -641,7 +642,7 @@ "AFL-3.0" ], "description": "Magento composer library helps to instantiate Composer application and run composer commands.", - "time": "2017-04-24T09:57:02+00:00" + "time": "2017-04-24 09:57:02" }, { "name": "magento/magento-composer-installer", @@ -720,7 +721,7 @@ "composer-installer", "magento" ], - "time": "2016-10-06T16:05:07+00:00" + "time": "2016-10-06 16:05:07" }, { "name": "magento/zendframework1", @@ -767,7 +768,7 @@ "ZF1", "framework" ], - "time": "2017-06-21T14:56:23+00:00" + "time": "2017-06-21 14:56:23" }, { "name": "monolog/monolog", @@ -845,7 +846,7 @@ "logging", "psr-3" ], - "time": "2017-06-19T01:22:40+00:00" + "time": "2017-06-19 01:22:40" }, { "name": "oyejorge/less.php", @@ -907,7 +908,7 @@ "php", "stylesheet" ], - "time": "2017-03-28T22:19:25+00:00" + "time": "2017-03-28 22:19:25" }, { "name": "paragonie/random_compat", @@ -955,7 +956,7 @@ "pseudorandom", "random" ], - "time": "2017-03-13T16:27:32+00:00" + "time": "2017-03-13 16:27:32" }, { "name": "pelago/emogrifier", @@ -1011,7 +1012,7 @@ ], "description": "Converts CSS styles into inline style attributes in your HTML code", "homepage": "http://www.pelagodesign.com/sidecar/emogrifier/", - "time": "2015-05-15T11:37:51+00:00" + "time": "2015-05-15 11:37:51" }, { "name": "phpseclib/phpseclib", @@ -1103,7 +1104,7 @@ "x.509", "x509" ], - "time": "2017-06-05T06:31:10+00:00" + "time": "2017-06-05 06:31:10" }, { "name": "psr/container", @@ -1152,7 +1153,7 @@ "container-interop", "psr" ], - "time": "2017-02-14T16:28:37+00:00" + "time": "2017-02-14 16:28:37" }, { "name": "psr/log", @@ -1199,7 +1200,7 @@ "psr", "psr-3" ], - "time": "2016-10-10T12:19:37+00:00" + "time": "2016-10-10 12:19:37" }, { "name": "ramsey/uuid", @@ -1281,7 +1282,7 @@ "identifier", "uuid" ], - "time": "2017-03-26T20:37:53+00:00" + "time": "2017-03-26 20:37:53" }, { "name": "seld/cli-prompt", @@ -1329,7 +1330,7 @@ "input", "prompt" ], - "time": "2017-03-18T11:32:45+00:00" + "time": "2017-03-18 11:32:45" }, { "name": "seld/jsonlint", @@ -1378,7 +1379,7 @@ "parser", "validator" ], - "time": "2017-06-18T15:11:04+00:00" + "time": "2017-06-18 15:11:04" }, { "name": "seld/phar-utils", @@ -1422,7 +1423,7 @@ "keywords": [ "phra" ], - "time": "2015-10-13T18:44:15+00:00" + "time": "2015-10-13 18:44:15" }, { "name": "sjparkinson/static-review", @@ -1475,7 +1476,7 @@ } ], "description": "An extendable framework for version control hooks.", - "time": "2014-09-22T08:40:36+00:00" + "time": "2014-09-22 08:40:36" }, { "name": "symfony/console", @@ -1536,7 +1537,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-08-27T14:29:03+00:00" + "time": "2017-08-27 14:29:03" }, { "name": "symfony/debug", @@ -1593,7 +1594,7 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2016-07-30T07:22:48+00:00" + "time": "2016-07-30 07:22:48" }, { "name": "symfony/event-dispatcher", @@ -1653,7 +1654,7 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2017-06-02T07:47:27+00:00" + "time": "2017-06-02 07:47:27" }, { "name": "symfony/filesystem", @@ -1702,7 +1703,7 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2017-07-29T21:54:42+00:00" + "time": "2017-07-29 21:54:42" }, { "name": "symfony/finder", @@ -1751,7 +1752,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2017-07-29T21:54:42+00:00" + "time": "2017-07-29 21:54:42" }, { "name": "symfony/polyfill-mbstring", @@ -1810,7 +1811,7 @@ "portable", "shim" ], - "time": "2017-06-14T15:44:48+00:00" + "time": "2017-06-14 15:44:48" }, { "name": "symfony/process", @@ -1859,7 +1860,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-07-03T08:04:30+00:00" + "time": "2017-07-03 08:04:30" }, { "name": "tedivm/jshrink", @@ -1905,7 +1906,7 @@ "javascript", "minifier" ], - "time": "2015-07-04T07:35:09+00:00" + "time": "2015-07-04 07:35:09" }, { "name": "tubalmartin/cssmin", @@ -1958,7 +1959,7 @@ "minify", "yui" ], - "time": "2017-05-16T13:45:26+00:00" + "time": "2017-05-16 13:45:26" }, { "name": "zendframework/zend-captcha", @@ -2015,7 +2016,7 @@ "captcha", "zf2" ], - "time": "2017-02-23T08:09:44+00:00" + "time": "2017-02-23 08:09:44" }, { "name": "zendframework/zend-code", @@ -2068,7 +2069,7 @@ "code", "zf2" ], - "time": "2016-10-24T13:23:32+00:00" + "time": "2016-10-24 13:23:32" }, { "name": "zendframework/zend-config", @@ -2124,7 +2125,7 @@ "config", "zf2" ], - "time": "2016-02-04T23:01:10+00:00" + "time": "2016-02-04 23:01:10" }, { "name": "zendframework/zend-console", @@ -2176,7 +2177,7 @@ "console", "zf2" ], - "time": "2016-02-09T17:15:12+00:00" + "time": "2016-02-09 17:15:12" }, { "name": "zendframework/zend-crypt", @@ -2226,7 +2227,7 @@ "crypt", "zf2" ], - "time": "2016-02-03T23:46:30+00:00" + "time": "2016-02-03 23:46:30" }, { "name": "zendframework/zend-db", @@ -2283,7 +2284,7 @@ "db", "zf2" ], - "time": "2016-08-09T19:28:55+00:00" + "time": "2016-08-09 19:28:55" }, { "name": "zendframework/zend-di", @@ -2330,7 +2331,7 @@ "di", "zf2" ], - "time": "2016-04-25T20:58:11+00:00" + "time": "2016-04-25 20:58:11" }, { "name": "zendframework/zend-escaper", @@ -2374,7 +2375,7 @@ "escaper", "zf2" ], - "time": "2016-06-30T19:48:38+00:00" + "time": "2016-06-30 19:48:38" }, { "name": "zendframework/zend-eventmanager", @@ -2421,7 +2422,7 @@ "eventmanager", "zf2" ], - "time": "2016-02-18T20:49:05+00:00" + "time": "2016-02-18 20:49:05" }, { "name": "zendframework/zend-filter", @@ -2481,7 +2482,7 @@ "filter", "zf2" ], - "time": "2017-05-17T20:56:17+00:00" + "time": "2017-05-17 20:56:17" }, { "name": "zendframework/zend-form", @@ -2558,7 +2559,7 @@ "form", "zf2" ], - "time": "2017-05-18T14:59:53+00:00" + "time": "2017-05-18 14:59:53" }, { "name": "zendframework/zend-http", @@ -2608,7 +2609,7 @@ "http", "zf2" ], - "time": "2017-01-31T14:41:02+00:00" + "time": "2017-01-31 14:41:02" }, { "name": "zendframework/zend-hydrator", @@ -2666,7 +2667,7 @@ "hydrator", "zf2" ], - "time": "2016-02-18T22:38:26+00:00" + "time": "2016-02-18 22:38:26" }, { "name": "zendframework/zend-i18n", @@ -2733,7 +2734,7 @@ "i18n", "zf2" ], - "time": "2017-05-17T17:00:12+00:00" + "time": "2017-05-17 17:00:12" }, { "name": "zendframework/zend-inputfilter", @@ -2788,7 +2789,7 @@ "inputfilter", "zf2" ], - "time": "2017-05-18T14:20:56+00:00" + "time": "2017-05-18 14:20:56" }, { "name": "zendframework/zend-json", @@ -2843,7 +2844,7 @@ "json", "zf2" ], - "time": "2016-02-04T21:20:26+00:00" + "time": "2016-02-04 21:20:26" }, { "name": "zendframework/zend-loader", @@ -2887,7 +2888,7 @@ "loader", "zf2" ], - "time": "2015-06-03T14:05:47+00:00" + "time": "2015-06-03 14:05:47" }, { "name": "zendframework/zend-log", @@ -2958,7 +2959,7 @@ "logging", "zf2" ], - "time": "2017-05-17T16:03:26+00:00" + "time": "2017-05-17 16:03:26" }, { "name": "zendframework/zend-math", @@ -3008,7 +3009,7 @@ "math", "zf2" ], - "time": "2016-04-07T16:29:53+00:00" + "time": "2016-04-07 16:29:53" }, { "name": "zendframework/zend-modulemanager", @@ -3066,7 +3067,7 @@ "modulemanager", "zf2" ], - "time": "2017-07-11T19:39:57+00:00" + "time": "2017-07-11 19:39:57" }, { "name": "zendframework/zend-mvc", @@ -3153,7 +3154,7 @@ "mvc", "zf2" ], - "time": "2016-02-23T15:24:59+00:00" + "time": "2016-02-23 15:24:59" }, { "name": "zendframework/zend-serializer", @@ -3210,7 +3211,7 @@ "serializer", "zf2" ], - "time": "2016-06-21T17:01:55+00:00" + "time": "2016-06-21 17:01:55" }, { "name": "zendframework/zend-server", @@ -3256,7 +3257,7 @@ "server", "zf2" ], - "time": "2016-06-20T22:27:55+00:00" + "time": "2016-06-20 22:27:55" }, { "name": "zendframework/zend-servicemanager", @@ -3308,7 +3309,7 @@ "servicemanager", "zf2" ], - "time": "2016-12-19T19:14:29+00:00" + "time": "2016-12-19 19:14:29" }, { "name": "zendframework/zend-session", @@ -3374,7 +3375,7 @@ "session", "zf2" ], - "time": "2017-06-19T21:31:39+00:00" + "time": "2017-06-19 21:31:39" }, { "name": "zendframework/zend-soap", @@ -3426,7 +3427,7 @@ "soap", "zf2" ], - "time": "2016-04-21T16:06:27+00:00" + "time": "2016-04-21 16:06:27" }, { "name": "zendframework/zend-stdlib", @@ -3485,7 +3486,7 @@ "stdlib", "zf2" ], - "time": "2016-04-12T21:17:31+00:00" + "time": "2016-04-12 21:17:31" }, { "name": "zendframework/zend-text", @@ -3532,7 +3533,7 @@ "text", "zf2" ], - "time": "2016-02-08T19:03:52+00:00" + "time": "2016-02-08 19:03:52" }, { "name": "zendframework/zend-uri", @@ -3579,7 +3580,7 @@ "uri", "zf2" ], - "time": "2016-02-17T22:38:51+00:00" + "time": "2016-02-17 22:38:51" }, { "name": "zendframework/zend-validator", @@ -3650,7 +3651,7 @@ "validator", "zf2" ], - "time": "2017-08-22T14:19:23+00:00" + "time": "2017-08-22 14:19:23" }, { "name": "zendframework/zend-view", @@ -3737,7 +3738,7 @@ "view", "zf2" ], - "time": "2017-03-21T15:05:56+00:00" + "time": "2017-03-21 15:05:56" } ], "packages-dev": [ @@ -3793,7 +3794,7 @@ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "time": "2015-06-14 21:17:01" }, { "name": "friendsofphp/php-cs-fixer", @@ -3863,7 +3864,7 @@ } ], "description": "A tool to automatically fix PHP code style", - "time": "2017-03-31T12:59:38+00:00" + "time": "2017-03-31 12:59:38" }, { "name": "ircmaxell/password-compat", @@ -3905,7 +3906,7 @@ "hashing", "password" ], - "time": "2014-11-20T16:49:30+00:00" + "time": "2014-11-20 16:49:30" }, { "name": "lusitanian/oauth", @@ -3972,7 +3973,7 @@ "oauth", "security" ], - "time": "2016-07-12T22:15:40+00:00" + "time": "2016-07-12 22:15:40" }, { "name": "myclabs/deep-copy", @@ -4014,7 +4015,7 @@ "object", "object graph" ], - "time": "2017-04-12T18:52:22+00:00" + "time": "2017-04-12 18:52:22" }, { "name": "pdepend/pdepend", @@ -4054,7 +4055,7 @@ "BSD-3-Clause" ], "description": "Official version of pdepend to be handled with Composer", - "time": "2017-01-19T14:23:36+00:00" + "time": "2017-01-19 14:23:36" }, { "name": "phar-io/manifest", @@ -4109,7 +4110,7 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-03-05T18:14:27+00:00" + "time": "2017-03-05 18:14:27" }, { "name": "phar-io/version", @@ -4156,7 +4157,7 @@ } ], "description": "Library for handling version information and constraints", - "time": "2017-03-05T17:38:23+00:00" + "time": "2017-03-05 17:38:23" }, { "name": "phpdocumentor/reflection-common", @@ -4210,7 +4211,7 @@ "reflection", "static analysis" ], - "time": "2017-09-11T18:02:19+00:00" + "time": "2017-09-11 18:02:19" }, { "name": "phpdocumentor/reflection-docblock", @@ -4255,7 +4256,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-08-30T18:51:59+00:00" + "time": "2017-08-30 18:51:59" }, { "name": "phpdocumentor/type-resolver", @@ -4302,7 +4303,7 @@ "email": "me@mikevanriel.com" } ], - "time": "2017-07-14T14:27:02+00:00" + "time": "2017-07-14 14:27:02" }, { "name": "phpmd/phpmd", @@ -4368,7 +4369,7 @@ "phpmd", "pmd" ], - "time": "2017-01-20T14:41:10+00:00" + "time": "2017-01-20 14:41:10" }, { "name": "phpspec/prophecy", @@ -4431,7 +4432,7 @@ "spy", "stub" ], - "time": "2017-09-04T11:05:03+00:00" + "time": "2017-09-04 11:05:03" }, { "name": "phpunit/php-code-coverage", @@ -4495,7 +4496,7 @@ "testing", "xunit" ], - "time": "2017-08-03T12:40:43+00:00" + "time": "2017-08-03 12:40:43" }, { "name": "phpunit/php-file-iterator", @@ -4542,7 +4543,7 @@ "filesystem", "iterator" ], - "time": "2016-10-03T07:40:28+00:00" + "time": "2016-10-03 07:40:28" }, { "name": "phpunit/php-text-template", @@ -4583,7 +4584,7 @@ "keywords": [ "template" ], - "time": "2015-06-21T13:50:34+00:00" + "time": "2015-06-21 13:50:34" }, { "name": "phpunit/php-timer", @@ -4632,7 +4633,7 @@ "keywords": [ "timer" ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2017-02-26 11:10:40" }, { "name": "phpunit/php-token-stream", @@ -4681,7 +4682,7 @@ "keywords": [ "tokenizer" ], - "time": "2017-08-20T05:47:52+00:00" + "time": "2017-08-20 05:47:52" }, { "name": "phpunit/phpunit", @@ -4765,7 +4766,7 @@ "testing", "xunit" ], - "time": "2017-08-03T13:59:28+00:00" + "time": "2017-08-03 13:59:28" }, { "name": "phpunit/phpunit-mock-objects", @@ -4824,7 +4825,7 @@ "mock", "xunit" ], - "time": "2017-08-03T14:08:16+00:00" + "time": "2017-08-03 14:08:16" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -4869,7 +4870,7 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04T06:30:41+00:00" + "time": "2017-03-04 06:30:41" }, { "name": "sebastian/comparator", @@ -4933,7 +4934,7 @@ "compare", "equality" ], - "time": "2017-03-03T06:26:08+00:00" + "time": "2017-03-03 06:26:08" }, { "name": "sebastian/diff", @@ -4985,7 +4986,7 @@ "keywords": [ "diff" ], - "time": "2017-05-22T07:24:03+00:00" + "time": "2017-05-22 07:24:03" }, { "name": "sebastian/environment", @@ -5035,7 +5036,7 @@ "environment", "hhvm" ], - "time": "2017-07-01T08:51:00+00:00" + "time": "2017-07-01 08:51:00" }, { "name": "sebastian/exporter", @@ -5102,7 +5103,7 @@ "export", "exporter" ], - "time": "2017-04-03T13:19:02+00:00" + "time": "2017-04-03 13:19:02" }, { "name": "sebastian/finder-facade", @@ -5141,7 +5142,7 @@ ], "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", "homepage": "https://github.com/sebastianbergmann/finder-facade", - "time": "2016-02-17T07:02:23+00:00" + "time": "2016-02-17 07:02:23" }, { "name": "sebastian/global-state", @@ -5192,7 +5193,7 @@ "keywords": [ "global state" ], - "time": "2017-04-27T15:39:26+00:00" + "time": "2017-04-27 15:39:26" }, { "name": "sebastian/object-enumerator", @@ -5239,7 +5240,7 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03T12:35:26+00:00" + "time": "2017-08-03 12:35:26" }, { "name": "sebastian/object-reflector", @@ -5284,7 +5285,7 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29T09:07:27+00:00" + "time": "2017-03-29 09:07:27" }, { "name": "sebastian/phpcpd", @@ -5335,7 +5336,7 @@ ], "description": "Copy/Paste Detector (CPD) for PHP code.", "homepage": "https://github.com/sebastianbergmann/phpcpd", - "time": "2016-04-17T19:32:49+00:00" + "time": "2016-04-17 19:32:49" }, { "name": "sebastian/recursion-context", @@ -5388,7 +5389,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-03T06:23:57+00:00" + "time": "2017-03-03 06:23:57" }, { "name": "sebastian/resource-operations", @@ -5430,7 +5431,7 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" + "time": "2015-07-28 20:34:47" }, { "name": "sebastian/version", @@ -5473,7 +5474,7 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" + "time": "2016-10-03 07:35:21" }, { "name": "squizlabs/php_codesniffer", @@ -5524,7 +5525,7 @@ "phpcs", "standards" ], - "time": "2017-06-14T01:23:49+00:00" + "time": "2017-06-14 01:23:49" }, { "name": "symfony/config", @@ -5586,7 +5587,7 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2017-09-04T16:28:07+00:00" + "time": "2017-09-04 16:28:07" }, { "name": "symfony/dependency-injection", @@ -5656,7 +5657,7 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2017-09-05T20:39:38+00:00" + "time": "2017-09-05 20:39:38" }, { "name": "symfony/polyfill-php54", @@ -5714,7 +5715,7 @@ "portable", "shim" ], - "time": "2017-06-14T15:44:48+00:00" + "time": "2017-06-14 15:44:48" }, { "name": "symfony/polyfill-php55", @@ -5770,7 +5771,7 @@ "portable", "shim" ], - "time": "2017-06-14T15:44:48+00:00" + "time": "2017-06-14 15:44:48" }, { "name": "symfony/polyfill-php70", @@ -5829,7 +5830,7 @@ "portable", "shim" ], - "time": "2017-06-14T15:44:48+00:00" + "time": "2017-06-14 15:44:48" }, { "name": "symfony/polyfill-php72", @@ -5884,7 +5885,7 @@ "portable", "shim" ], - "time": "2017-07-11T13:25:55+00:00" + "time": "2017-07-11 13:25:55" }, { "name": "symfony/polyfill-xml", @@ -5932,7 +5933,7 @@ "portable", "shim" ], - "time": "2017-06-14T15:44:48+00:00" + "time": "2017-06-14 15:44:48" }, { "name": "symfony/stopwatch", @@ -5981,7 +5982,7 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2017-07-29T21:54:42+00:00" + "time": "2017-07-29 21:54:42" }, { "name": "theseer/fdomdocument", @@ -6021,7 +6022,7 @@ ], "description": "The classes contained within this repository extend the standard DOM to use exceptions at all occasions of errors instead of PHP warnings or notices. They also add various custom methods and shortcuts for convenience and to simplify the usage of DOM.", "homepage": "https://github.com/theseer/fDOMDocument", - "time": "2017-06-30T11:53:12+00:00" + "time": "2017-06-30 11:53:12" }, { "name": "theseer/tokenizer", @@ -6061,7 +6062,7 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2017-04-07T12:08:54+00:00" + "time": "2017-04-07 12:08:54" }, { "name": "webmozart/assert", @@ -6111,7 +6112,7 @@ "check", "validate" ], - "time": "2016-11-23T20:04:58+00:00" + "time": "2016-11-23 20:04:58" } ], "aliases": [], From 2ab293917b54d4dd3ef11ead3701d5601f5a0451 Mon Sep 17 00:00:00 2001 From: Joan He Date: Mon, 2 Oct 2017 17:22:30 -0500 Subject: [PATCH 005/194] MAGETWO-80475: Start subscription after Magento installed/upgraded --- .../Backend/Enabled/SubscriptionHandler.php | 24 +++++----- .../Magento/Analytics/Setup/InstallData.php | 46 +++++++++++-------- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php index 95caceddebc88..03f3ddaeebbaa 100644 --- a/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php +++ b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php @@ -28,6 +28,17 @@ class SubscriptionHandler */ const CRON_STRING_PATH = 'crontab/default/jobs/analytics_subscribe/schedule/cron_expr'; + /** + * Config value for schedule setting of subscription handler. + */ + const CRON_EXPR_ARRAY = [ + '0', # Minute + '*', # Hour + '*', # Day of the Month + '*', # Month of the Year + '*', # Day of the Week + ]; + /** * Max value for reserve counter of attempts to subscribe. * @@ -124,18 +135,7 @@ public function processEnabled() */ private function setCronSchedule() { - $cronExprArray = [ - '0', # Minute - '*', # Hour - '*', # Day of the Month - '*', # Month of the Year - '*', # Day of the Week - ]; - - $cronExprString = join(' ', $cronExprArray); - - $this->configWriter->save(self::CRON_STRING_PATH, $cronExprString); - + $this->configWriter->save(self::CRON_STRING_PATH, join(' ', self::CRON_EXPR_ARRAY)); return true; } diff --git a/app/code/Magento/Analytics/Setup/InstallData.php b/app/code/Magento/Analytics/Setup/InstallData.php index 302cf00f9091f..5a67a6d5e6765 100644 --- a/app/code/Magento/Analytics/Setup/InstallData.php +++ b/app/code/Magento/Analytics/Setup/InstallData.php @@ -6,10 +6,10 @@ namespace Magento\Analytics\Setup; +use Magento\Analytics\Model\Config\Backend\Enabled\SubscriptionHandler; use Magento\Framework\Setup\InstallDataInterface; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\ModuleDataSetupInterface; -use Magento\Analytics\Model\NotificationTime; /** * @codeCoverageIgnore @@ -17,23 +17,6 @@ */ class InstallData implements InstallDataInterface { - /** - * @var NotificationTime - * @since 2.2.0 - */ - private $notificationTime; - - /** - * InstallData constructor. - * - * @param NotificationTime $notificationTime - * @since 2.2.0 - */ - public function __construct( - NotificationTime $notificationTime - ) { - $this->notificationTime = $notificationTime; - } /** * {@inheritdoc} @@ -42,6 +25,31 @@ public function __construct( */ public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) { - $this->notificationTime->storeLastTimeNotification(1); + $setup->getConnection()->insertMultiple( + $setup->getTable('core_config_data'), + [ + [ + 'scope' => 'default', + 'scope_id' => 0, + 'path' => 'analytics/subscription/enabled', + 'value' => 1 + ], + [ + 'scope' => 'default', + 'scope_id' => 0, + 'path' => SubscriptionHandler::CRON_STRING_PATH, + 'value' => join(' ', SubscriptionHandler::CRON_EXPR_ARRAY) + ] + ] + ); + + $setup->getConnection()->insert( + $setup->getTable('flag'), + [ + 'flag_code' => SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, + 'state' => 0, + 'flag_data' => 24, + ] + ); } } From 124f3932b6cd7fd3a4b6cefd9c5876a541c8b6f5 Mon Sep 17 00:00:00 2001 From: Stanislav Idolov Date: Tue, 3 Oct 2017 16:00:55 +0300 Subject: [PATCH 006/194] MAGETWO-80191: [2.2.x] - Fixes #10255: base_shipping_discount_tax_compensation_amnt was empty from order onwards #10435 --- app/code/Magento/Sales/etc/fieldset.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/etc/fieldset.xml b/app/code/Magento/Sales/etc/fieldset.xml index 3d29575063fef..2132e05dd8a9d 100644 --- a/app/code/Magento/Sales/etc/fieldset.xml +++ b/app/code/Magento/Sales/etc/fieldset.xml @@ -279,7 +279,7 @@ - + From 0e24d0bcfc86027dd6efce08b3792ea468e4f5f3 Mon Sep 17 00:00:00 2001 From: Stanislav Idolov Date: Tue, 3 Oct 2017 16:53:19 +0300 Subject: [PATCH 007/194] MAGETWO-80191: [2.2.x] - Fixes #10255: base_shipping_discount_tax_compensation_amnt was empty from order onwards #10435 --- .../Model/Quote/Address/ConverterTest.php | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Address/ConverterTest.php diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Address/ConverterTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Address/ConverterTest.php new file mode 100644 index 0000000000000..cfb1967bf09d5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Address/ConverterTest.php @@ -0,0 +1,46 @@ +objectManager = Bootstrap::getObjectManager(); + $this->objectCopyService = $this->objectManager->create(\Magento\Framework\DataObject\Copy::class); + } + + public function testThatFieldBaseShippingDiscountTaxCompensationAmountPresentInOrderAddress() + { + $amountValue = 999.99; + /** @var \Magento\Quote\Model\Quote\Address $quoteAddress */ + $quoteAddress = $this->objectManager->create(\Magento\Quote\Model\Quote\Address::class); + $quoteAddress->setBaseShippingDiscountTaxCompensationAmount($amountValue); + + $orderAddressData = $this->objectCopyService->getDataFromFieldset( + 'sales_convert_quote_address', + 'to_order', + $quoteAddress + ); + + $this->assertArrayHasKey('base_shipping_discount_tax_compensation_amnt', $orderAddressData); + $this->assertEquals($amountValue, $orderAddressData['base_shipping_discount_tax_compensation_amnt']); + } +} From ae46c87691cc2a239378f452896fea582c96d701 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 3 Oct 2017 15:37:06 -0500 Subject: [PATCH 008/194] MAGETWO-80479: Update existing Advanced Reporting tests - Remove obsolete tests --- .../Analytics/Test/TestCase/InstallTest.xml | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml deleted file mode 100644 index 8e19e1116da19..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - severity:S1 - Apps and Games - - - - - - severity:S1 - - - - - severity:S1 - - - - - From 73cd1ea0824b39d381448b4d6ea9dfb7f81e58a0 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 3 Oct 2017 16:22:11 -0500 Subject: [PATCH 009/194] MAGETWO-80479: Update existing Advanced Reporting tests - Remove obsolete tests --- ...lyticsSubscriptionCheckPermissionsTest.php | 37 ------------------- ...lyticsSubscriptionCheckPermissionsTest.xml | 15 -------- 2 files changed, 52 deletions(-) delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php deleted file mode 100644 index 2fe656081d162..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php +++ /dev/null @@ -1,37 +0,0 @@ -executeScenario(); - } -} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml deleted file mode 100644 index f3ed3736e2ea2..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - custom_admin_with_role_without_subscription_permissions - - - - From 25202a0e504108397616405987daf473e7779eaf Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 4 Oct 2017 13:38:02 -0500 Subject: [PATCH 010/194] MAGETWO-80474: Update Advanced Reporting Configuration Page --- .../Adminhtml/System/Config/Vertical.php | 43 +++++++++++ .../Adminhtml/System/Config/VerticalTest.php | 76 +++++++++++++++++++ .../Analytics/etc/adminhtml/system.xml | 24 +++--- .../web/css/source/_module.less | 24 ++++++ 4 files changed, 156 insertions(+), 11 deletions(-) create mode 100644 app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php new file mode 100644 index 0000000000000..be3d8eabc899b --- /dev/null +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php @@ -0,0 +1,43 @@ +' . $element->getHint() . ''; + $html .= '
' . $element->getComment() . '
'; + return $this->decorateRowHtml($element, $html); + } + + /** + * @param \Magento\Framework\Data\Form\Element\AbstractElement $element + * @param string $html + * @return string + * @since 2.2.2 + */ + private function decorateRowHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element, $html) + { + $rowHtml = sprintf('%s', $html); + $rowHtml .= sprintf( + '%s%s', + $element->getHtmlId(), + $element->getLabelHtml($element->getHtmlId(), "[WEBSITE]"), + $element->getElementHtml() + ); + return $rowHtml; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php new file mode 100644 index 0000000000000..331b487e5dd9d --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php @@ -0,0 +1,76 @@ +abstractElementMock = $this->getMockBuilder(AbstractElement::class) + ->setMethods(['getComment', 'getLabel', 'getHint']) + ->disableOriginalConstructor() + ->getMock(); + $this->contextMock = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->getMock(); + $this->formMock = $this->getMockBuilder(Form::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->vertical = new Vertical($this->contextMock); + } + + /** + * @return void + */ + public function testRender() + { + $this->abstractElementMock->setForm($this->formMock); + $this->abstractElementMock->expects($this->any()) + ->method('getComment') + ->willReturn('New comment'); + $this->abstractElementMock->expects($this->any()) + ->method('getHint') + ->willReturn('New hint'); + $html = $this->vertical->render($this->abstractElementMock); + $this->assertRegexp( + "/New comment/", + $html + ); + $this->assertRegExp( + "/New hint/", + $html + ); + } +} diff --git a/app/code/Magento/Analytics/etc/adminhtml/system.xml b/app/code/Magento/Analytics/etc/adminhtml/system.xml index 32d493451ca61..3d87c24176c81 100644 --- a/app/code/Magento/Analytics/etc/adminhtml/system.xml +++ b/app/code/Magento/Analytics/etc/adminhtml/system.xml @@ -13,10 +13,9 @@ Magento_Analytics::analytics_settings - For more information, view details or see our - terms and conditions.]]> + For more information, see our terms and conditions.]]> Magento\Config\Model\Config\Source\Enabledisable @@ -24,21 +23,24 @@ Magento\Analytics\Block\Adminhtml\System\Config\SubscriptionStatusLabel analytics/subscription/enabled - - - Magento\Analytics\Model\Config\Source\Vertical - Magento\Analytics\Model\Config\Backend\Vertical - - + Magento\Analytics\Block\Adminhtml\System\Config\CollectionTimeLabel Magento\Analytics\Model\Config\Backend\CollectionTime + + Industry Data + + In order to personalize your Advanced Reporting experience, please select your industry. + Magento\Analytics\Model\Config\Source\Vertical + Magento\Analytics\Model\Config\Backend\Vertical + Magento\Analytics\Block\Adminhtml\System\Config\Vertical + Learn more about BI Essentials tier.]]> + href="https://dashboard.rjmetrics.com/v2/magento/signup/">Magento BI Essentials and BI Pro tiers.]]> Magento\Analytics\Block\Adminhtml\System\Config\AdditionalComment diff --git a/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less index db29bfcaf6355..85454effcbd67 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less @@ -190,3 +190,27 @@ .config-additional-comment-content { line-height: @line-height__l; } + +.config-vertical-title { + clear: both; + color: #303030; + font-size: 1.7rem; + font-weight: 600; + letter-spacing: .025em; + padding: 1.9rem 2.8rem 1.9rem 0; + position: relative; +} + +.config-vertical-comment { + line-height: 1.5; + margin-bottom: .5em; + margin-top: 1rem; +} + +#row_analytics_general_vertical { + >td.config-vertical-label { + >label.admin__field-label { + padding-right: 0; + } + } +} From 79bc973e7a82637aff1cd4a94c4504f9e391c86f Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 4 Oct 2017 15:17:25 -0500 Subject: [PATCH 011/194] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- .../Adminhtml/Subscription/Activate.php | 142 ---------- .../Adminhtml/Subscription/Postpone.php | 103 ------- .../Model/Condition/CanViewNotification.php | 47 +--- .../Backend/Enabled/SubscriptionHandler.php | 13 - .../Analytics/Model/NotificationTime.php | 51 ++-- .../Adminhtml/Subscription/ActivateTest.php | 252 ------------------ .../Adminhtml/Subscription/PostponeTest.php | 168 ------------ .../Condition/CanViewNotificationTest.php | 41 +-- .../Enabled/SubscriptionHandlerTest.php | 17 -- .../Test/Unit/Model/NotificationTimeTest.php | 76 +++++- .../layout/adminhtml_dashboard_index.xml | 2 +- .../analytics_subscription_form.xml | 247 ----------------- .../analytics_subscription_notification.xml | 98 +++++++ .../adminhtml/web/js/modal/modal-component.js | 66 ----- .../web/template/buttons-container.html | 13 - .../form/components/single/checkbox.html | 17 -- .../web/css/source/_module.less | 189 +++++-------- .../web/images/advanced-reporting-badge.svg | 7 + .../AdvancedReporting/SubscriptionBlock.php | 71 +---- 19 files changed, 302 insertions(+), 1318 deletions(-) delete mode 100644 app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php delete mode 100644 app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php delete mode 100644 app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php delete mode 100644 app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php delete mode 100644 app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_form.xml create mode 100644 app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml delete mode 100644 app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js delete mode 100644 app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html delete mode 100644 app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html create mode 100644 app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/advanced-reporting-badge.svg diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php deleted file mode 100644 index 59923e82ef46c..0000000000000 --- a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php +++ /dev/null @@ -1,142 +0,0 @@ -logger = $logger; - $this->notificationTime = $notificationTime; - $this->configValueResource = $configValueResource; - $this->preparedValueFactory = $preparedValueFactory; - parent::__construct($context); - } - - /** - * Check admin permissions for this controller - * - * @return boolean - * @since 2.2.0 - */ - protected function _isAllowed() - { - return $this->_authorization->isAllowed('Magento_Analytics::analytics_settings'); - } - - /** - * Activate subscription to Magento BI via AJAX. - * - * @return Json - * @since 2.2.0 - */ - public function execute() - { - try { - if ($this->getRequest()->getParam($this->subscriptionApprovedField)) { - $configValue = $this->preparedValueFactory->create( - Enabled::XML_ENABLED_CONFIG_STRUCTURE_PATH, - Enabledisable::ENABLE_VALUE, - ScopeConfigInterface::SCOPE_TYPE_DEFAULT - ); - - $this->configValueResource - ->save($configValue); - } else { - $this->notificationTime->unsetLastTimeNotificationValue(); - } - $responseContent = [ - 'success' => true, - 'error_message' => '', - ]; - } catch (LocalizedException $e) { - $responseContent = [ - 'success' => false, - 'error_message' => $e->getMessage(), - ]; - $this->logger->error($e->getMessage()); - } catch (\Exception $e) { - $responseContent = [ - 'success' => false, - 'error_message' => __( - 'Sorry, there was an error processing your registration request to Magento Analytics. ' - . 'Please try again later.' - ), - ]; - $this->logger->error($e->getMessage()); - } - /** @var Json $resultJson */ - $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON); - return $resultJson->setData($responseContent); - } -} diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php deleted file mode 100644 index 068416157ae6a..0000000000000 --- a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php +++ /dev/null @@ -1,103 +0,0 @@ -dateTimeFactory = $dateTimeFactory; - $this->notificationTime = $notificationTime; - $this->logger = $logger; - parent::__construct($context); - } - - /** - * Check admin permissions for this controller - * - * @return boolean - * @since 2.2.0 - */ - protected function _isAllowed() - { - return $this->_authorization->isAllowed('Magento_Analytics::analytics_settings'); - } - - /** - * Postpones notification about subscription - * - * @return Json - * @since 2.2.0 - */ - public function execute() - { - try { - $dateTime = $this->dateTimeFactory->create(); - $responseContent = [ - 'success' => $this->notificationTime->storeLastTimeNotification($dateTime->getTimestamp()), - 'error_message' => '' - ]; - } catch (LocalizedException $e) { - $this->logger->error($e->getMessage()); - $responseContent = [ - 'success' => false, - 'error_message' => $e->getMessage() - ]; - } catch (\Exception $e) { - $this->logger->error($e->getMessage()); - $responseContent = [ - 'success' => false, - 'error_message' => __('Error occurred during postponement notification') - ]; - } - /** @var Json $resultJson */ - $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON); - return $resultJson->setData($responseContent); - } -} diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php index 9200361322dc2..157a033959c42 100644 --- a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -7,14 +7,13 @@ use Magento\Framework\View\Layout\Condition\VisibilityConditionInterface; use Magento\Analytics\Model\NotificationTime; -use Magento\Framework\Intl\DateTimeFactory; /** * Class CanViewNotification * - * Dynamic validator for UI signUp notification form, manage Ui component visibility. - * Return true if last notification was shipped seven days ago. - * @since 2.2.0 + * Dynamic validator for UI analytics notification, manage UI component visibility. + * Return true if the logged in user has not seen the notification. + * @since 2.2.2 */ class CanViewNotification implements VisibilityConditionInterface { @@ -23,62 +22,44 @@ class CanViewNotification implements VisibilityConditionInterface */ const NAME = 'can_view_notification'; - /** - * Time interval in seconds - * - * @var int - * @since 2.2.0 - */ - private $notificationInterval = 604800; - /** * @var NotificationTime - * @since 2.2.0 + * @since 2.2.2 */ private $notificationTime; - /** - * @var DateTimeFactory - * @since 2.2.0 - */ - private $dateTimeFactory; - /** * CanViewNotification constructor. * * @param NotificationTime $notificationTime - * @param DateTimeFactory $dateTimeFactory - * @since 2.2.0 + * @since 2.2.2 */ public function __construct( - NotificationTime $notificationTime, - DateTimeFactory $dateTimeFactory + NotificationTime $notificationTime ) { $this->notificationTime = $notificationTime; - $this->dateTimeFactory = $dateTimeFactory; } /** - * Validate is notification popup can be shown + * Validate if notification popup can be shown * * @inheritdoc - * @since 2.2.0 + * @since 2.2.2 */ public function isVisible(array $arguments) { - $lastNotificationTime = $this->notificationTime->getLastTimeNotification(); - if (!$lastNotificationTime) { + $lastNotificationTime = $this->notificationTime->getLastTimeNotificationForCurrentUser(); + + if ($lastNotificationTime) { return false; } - $datetime = $this->dateTimeFactory->create(); - return ( - $datetime->getTimestamp() >= $lastNotificationTime + $this->notificationInterval - ); + + return $this->notificationTime->storeLastTimeNotificationForCurrentUser(); } /** * @return string - * @since 2.2.0 + * @since 2.2.2 */ public function getName() { diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php index 03f3ddaeebbaa..04202cdcda11c 100644 --- a/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php +++ b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php @@ -7,7 +7,6 @@ use Magento\Analytics\Model\AnalyticsToken; use Magento\Analytics\Model\Config\Backend\CollectionTime; -use Magento\Analytics\Model\NotificationTime; use Magento\Framework\App\Config\ReinitableConfigInterface; use Magento\Framework\App\Config\Storage\WriterInterface; use Magento\Framework\FlagManager; @@ -71,14 +70,6 @@ class SubscriptionHandler */ private $analyticsToken; - /** - * Resource for managing last notification time about subscription to Magento Analytics. - * - * @var NotificationTime - * @since 2.2.0 - */ - private $notificationTime; - /** * @var ReinitableConfigInterface * @since 2.2.0 @@ -89,7 +80,6 @@ class SubscriptionHandler * @param WriterInterface $configWriter * @param FlagManager $flagManager * @param AnalyticsToken $analyticsToken - * @param NotificationTime $notificationTime * @param ReinitableConfigInterface $reinitableConfig * @since 2.2.0 */ @@ -97,13 +87,11 @@ public function __construct( WriterInterface $configWriter, FlagManager $flagManager, AnalyticsToken $analyticsToken, - NotificationTime $notificationTime, ReinitableConfigInterface $reinitableConfig ) { $this->configWriter = $configWriter; $this->flagManager = $flagManager; $this->analyticsToken = $analyticsToken; - $this->notificationTime = $notificationTime; $this->reinitableConfig = $reinitableConfig; } @@ -120,7 +108,6 @@ public function processEnabled() if (!$this->analyticsToken->isTokenExist()) { $this->setCronSchedule(); $this->setAttemptsFlag(); - $this->notificationTime->unsetLastTimeNotificationValue(); $this->reinitableConfig->reinit(); } diff --git a/app/code/Magento/Analytics/Model/NotificationTime.php b/app/code/Magento/Analytics/Model/NotificationTime.php index c36f830a70762..b831c4e20dc5f 100644 --- a/app/code/Magento/Analytics/Model/NotificationTime.php +++ b/app/code/Magento/Analytics/Model/NotificationTime.php @@ -6,67 +6,88 @@ namespace Magento\Analytics\Model; use Magento\Framework\FlagManager; +use Magento\Authorization\Model\UserContextInterface; +use Magento\Framework\Intl\DateTimeFactory; /** * Class NotificationTime * * Manage access to notification time flag * - * @since 2.2.0 + * @since 2.2.2 */ class NotificationTime { - const NOTIFICATION_TIME = 'notification_time'; + const NOTIFICATION_TIME = 'analytics_notification_time_admin_'; /** * @var FlagManager - * @since 2.2.0 + * @since 2.2.2 */ private $flagManager; + /** + * @var UserContextInterface + * @since 2.2.2 + */ + private $userContext; + + /** + * @var DateTimeFactory + * @since 2.2.2 + */ + private $dateTimeFactory; + /** * NotificationTime constructor. * * @param FlagManager $flagManager - * @since 2.2.0 + * @param UserContextInterface $userContext + * @param DateTimeFactory $dateTimeFactory + * @since 2.2.2 */ public function __construct( - FlagManager $flagManager + FlagManager $flagManager, + UserContextInterface $userContext, + DateTimeFactory $dateTimeFactory ) { $this->flagManager = $flagManager; + $this->userContext = $userContext; + $this->dateTimeFactory = $dateTimeFactory; } /** * Stores last notification time * - * @param string $value * @return bool - * @since 2.2.0 + * @since 2.2.2 */ - public function storeLastTimeNotification($value) + public function storeLastTimeNotificationForCurrentUser() { - return $this->flagManager->saveFlag(self::NOTIFICATION_TIME, $value); + $flagCode = self::NOTIFICATION_TIME . $this->userContext->getUserId(); + $dateTime = $this->dateTimeFactory->create(); + return $this->flagManager->saveFlag($flagCode, $dateTime->getTimestamp()); } /** * Returns last time when merchant was notified about Analytic services * * @return int - * @since 2.2.0 + * @since 2.2.2 */ - public function getLastTimeNotification() + public function getLastTimeNotificationForCurrentUser() { - return $this->flagManager->getFlagData(self::NOTIFICATION_TIME); + return $this->flagManager->getFlagData(self::NOTIFICATION_TIME . $this->userContext->getUserId()); } /** * Remove last notification time flag. * * @return bool - * @since 2.2.0 + * @since 2.2.2 */ - public function unsetLastTimeNotificationValue() + public function unsetLastTimeNotificationValueForCurrentUser() { - return $this->flagManager->deleteFlag(self::NOTIFICATION_TIME); + return $this->flagManager->deleteFlag(self::NOTIFICATION_TIME . $this->userContext->getUserId()); } } diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php deleted file mode 100644 index 66c7ae4fac448..0000000000000 --- a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php +++ /dev/null @@ -1,252 +0,0 @@ -resultFactoryMock = $this->getMockBuilder(ResultFactory::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->resultJsonMock = $this->getMockBuilder(Json::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->preparedValueFactoryMock = $this->getMockBuilder(PreparedValueFactory::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->configValueResourceMock = $this->getMockBuilder(AbstractDb::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->requestMock = $this->getMockBuilder(RequestInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->objectManagerHelper = new ObjectManagerHelper($this); - - $this->activateController = $this->objectManagerHelper->getObject( - Activate::class, - [ - 'resultFactory' => $this->resultFactoryMock, - 'preparedValueFactory' => $this->preparedValueFactoryMock, - 'configValueResource' => $this->configValueResourceMock, - 'logger' => $this->loggerMock, - 'notificationTime' => $this->notificationTimeMock, - '_request' => $this->requestMock, - 'subscriptionApprovedFiled' => $this->subscriptionApprovedField, - ] - ); - } - - /** - * @dataProvider executeDataProvider - * - * @param bool $isSubscriptionEnabled - * @return void - */ - public function testExecute($isSubscriptionEnabled) - { - $successResult = [ - 'success' => true, - 'error_message' => '', - ]; - - $this->requestMock - ->expects($this->once()) - ->method('getParam') - ->with($this->subscriptionApprovedField) - ->willReturn($isSubscriptionEnabled); - - if ($isSubscriptionEnabled) { - $configValue = $this->createConfigValueMock(); - $this->preparedValueFactoryMock - ->expects($this->once()) - ->method('create') - ->willReturn($configValue); - $this->configValueResourceMock->expects($this->once())->method('save')->with($configValue); - } else { - $this->notificationTimeMock - ->expects($this->once()) - ->method('unsetLastTimeNotificationValue') - ->willReturn(true); - } - - $this->resultFactoryMock->expects($this->once()) - ->method('create') - ->with(ResultFactory::TYPE_JSON) - ->willReturn($this->resultJsonMock); - $this->resultJsonMock->expects($this->once()) - ->method('setData') - ->with($successResult) - ->willReturnSelf(); - $this->assertSame( - $this->resultJsonMock, - $this->activateController->execute() - ); - } - - /** - * @dataProvider executeExceptionsDataProvider - * - * @param \Exception $exception - */ - public function testExecuteWithException(\Exception $exception) - { - $this->requestMock - ->expects($this->once()) - ->method('getParam') - ->with($this->subscriptionApprovedField) - ->willReturn(true); - - $this->preparedValueFactoryMock - ->expects($this->once()) - ->method('create') - ->willThrowException($exception); - $this->loggerMock - ->expects($this->once()) - ->method('error') - ->with($exception->getMessage()); - $this->resultFactoryMock - ->expects($this->once()) - ->method('create') - ->with(ResultFactory::TYPE_JSON) - ->willReturn($this->resultJsonMock); - - if ($exception instanceof LocalizedException) { - $this->resultJsonMock - ->expects($this->once()) - ->method('setData') - ->with([ - 'success' => false, - 'error_message' => $exception->getMessage(), - ]) - ->willReturnSelf(); - } else { - $this->resultJsonMock - ->expects($this->once()) - ->method('setData') - ->withAnyParameters() - ->willReturnSelf(); - } - - $this->assertSame( - $this->resultJsonMock, - $this->activateController->execute() - ); - } - - /** - * @return \PHPUnit_Framework_MockObject_MockObject - */ - private function createConfigValueMock() - { - return $this->getMockBuilder(\Magento\Framework\Model\AbstractModel::class) - ->disableOriginalConstructor() - ->getMock(); - } - - /** - * @return array - */ - public function executeExceptionsDataProvider() - { - return [ - [new LocalizedException(__('TestMessage'))], - [new \Exception('TestMessage')], - ]; - } - - /** - * @return array - */ - public function executeDataProvider() - { - return [ - [true], - [false], - ]; - } -} diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php deleted file mode 100644 index 1fb7126146767..0000000000000 --- a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php +++ /dev/null @@ -1,168 +0,0 @@ -dateTimeFactoryMock = $this->getMockBuilder(DateTimeFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->dateTimeMock = $this->getMockBuilder(\DateTime::class) - ->disableOriginalConstructor() - ->getMock(); - $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) - ->disableOriginalConstructor() - ->getMock(); - $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) - ->getMock(); - $this->resultFactoryMock = $this->getMockBuilder(ResultFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->resultMock = $this->getMockBuilder(Json::class) - ->disableOriginalConstructor() - ->getMock(); - $this->resultFactoryMock->expects($this->once()) - ->method('create') - ->with(ResultFactory::TYPE_JSON) - ->willReturn($this->resultMock); - $objectManagerHelper = new ObjectManagerHelper($this); - $this->action = $objectManagerHelper->getObject( - Postpone::class, - [ - 'resultFactory' => $this->resultFactoryMock, - 'dateTimeFactory' => $this->dateTimeFactoryMock, - 'notificationTime' => $this->notificationTimeMock, - 'logger' => $this->loggerMock - ] - ); - } - - public function testExecuteSuccess() - { - $this->dateTimeFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->dateTimeMock); - $this->dateTimeMock->expects($this->once()) - ->method('getTimestamp') - ->willReturn(100500); - $this->notificationTimeMock->expects($this->once()) - ->method('storeLastTimeNotification') - ->with(100500) - ->willReturn(true); - $this->resultMock->expects($this->once()) - ->method('setData') - ->with( - [ - 'success' => true, - 'error_message' => '' - ], - false, - [] - )->willReturnSelf(); - $this->assertEquals($this->resultMock, $this->action->execute()); - } - - public function testExecuteFailedWithLocalizedException() - { - $this->dateTimeFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->dateTimeMock); - $this->dateTimeMock->expects($this->once()) - ->method('getTimestamp') - ->willReturn(100500); - $this->notificationTimeMock->expects($this->once()) - ->method('storeLastTimeNotification') - ->with(100500) - ->willThrowException(new LocalizedException(__('Error message'))); - $this->resultMock->expects($this->once()) - ->method('setData') - ->with( - [ - 'success' => false, - 'error_message' => 'Error message' - ], - false, - [] - )->willReturnSelf(); - $this->assertEquals($this->resultMock, $this->action->execute()); - } - - public function testExecuteFailedWithException() - { - $this->dateTimeFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->dateTimeMock); - $this->dateTimeMock->expects($this->once()) - ->method('getTimestamp') - ->willReturn(100500); - $this->notificationTimeMock->expects($this->once()) - ->method('storeLastTimeNotification') - ->with(100500) - ->willThrowException(new \Exception('Any message')); - $this->resultMock->expects($this->once()) - ->method('setData') - ->with( - [ - 'success' => false, - 'error_message' => __('Error occurred during postponement notification') - ], - false, - [] - )->willReturnSelf(); - $this->assertEquals($this->resultMock, $this->action->execute()); - } -} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index 755db7e0b3ab1..b12325a0ee511 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -9,7 +9,6 @@ use Magento\Analytics\Model\Condition\CanViewNotification; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Analytics\Model\NotificationTime; -use Magento\Framework\Intl\DateTimeFactory; /** * Class CanViewNotificationTest @@ -21,16 +20,6 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase */ private $notificationTimeMock; - /** - * @var DateTimeFactory|\PHPUnit_Framework_MockObject_MockObject - */ - private $dateTimeFactoryMock; - - /** - * @var \DateTime|\PHPUnit_Framework_MockObject_MockObject - */ - private $dateTimeMock; - /** * @var CanViewNotification */ @@ -38,10 +27,6 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase public function setUp() { - $this->dateTimeFactoryMock = $this->getMockBuilder(DateTimeFactory::class) - ->getMock(); - $this->dateTimeMock = $this->getMockBuilder(\DateTime::class) - ->getMock(); $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) ->disableOriginalConstructor() ->getMock(); @@ -49,33 +34,27 @@ public function setUp() $this->canViewNotification = $objectManager->getObject( CanViewNotification::class, [ - 'notificationTime' => $this->notificationTimeMock, - 'dateTimeFactory' => $this->dateTimeFactoryMock + 'notificationTime' => $this->notificationTimeMock ] ); } - public function testValidate() + public function testUserShouldSeeNotification() { $this->notificationTimeMock->expects($this->once()) - ->method('getLastTimeNotification') - ->willReturn(1); - $this->dateTimeFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->dateTimeMock); - $this->dateTimeMock->expects($this->once()) - ->method('getTimestamp') - ->willReturn(10005000); + ->method('getLastTimeNotificationForCurrentUser') + ->willReturn(false); + $this->notificationTimeMock->expects($this->once()) + ->method('storeLastTimeNotificationForCurrentUser') + ->willReturn(true); $this->assertTrue($this->canViewNotification->isVisible([])); } - public function testValidateFlagRemoved() + public function testUserShouldNotSeeNotification() { $this->notificationTimeMock->expects($this->once()) - ->method('getLastTimeNotification') - ->willReturn(null); - $this->dateTimeFactoryMock->expects($this->never()) - ->method('create'); + ->method('getLastTimeNotificationForCurrentUser') + ->willReturn(true); $this->assertFalse($this->canViewNotification->isVisible([])); } } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php index e5ec3f80322a9..ff3b807e5d8c5 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php @@ -34,11 +34,6 @@ class SubscriptionHandlerTest extends \PHPUnit\Framework\TestCase */ private $tokenMock; - /** - * @var NotificationTime|\PHPUnit_Framework_MockObject_MockObject - */ - private $notificationTimeMock; - /** * @var ObjectManagerHelper */ @@ -71,10 +66,6 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) - ->disableOriginalConstructor() - ->getMock(); - $this->objectManagerHelper = new ObjectManagerHelper($this); $this->subscriptionHandler = $this->objectManagerHelper->getObject( @@ -84,7 +75,6 @@ protected function setUp() 'configWriter' => $this->configWriterMock, 'attemptsInitValue' => $this->attemptsInitValue, 'analyticsToken' => $this->tokenMock, - 'notificationTime' => $this->notificationTimeMock, ] ); } @@ -104,9 +94,6 @@ public function testProcessEnabledTokenExist() $this->flagManagerMock ->expects($this->never()) ->method('saveFlag'); - $this->notificationTimeMock - ->expects($this->never()) - ->method('unsetLastTimeNotificationValue'); $this->assertTrue( $this->subscriptionHandler->processEnabled() ); @@ -130,10 +117,6 @@ public function testProcessEnabledTokenDoesNotExist() ->method('saveFlag') ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, $this->attemptsInitValue) ->willReturn(true); - $this->notificationTimeMock - ->expects($this->once()) - ->method('unsetLastTimeNotificationValue') - ->willReturn(true); $this->assertTrue( $this->subscriptionHandler->processEnabled() ); diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php index 581cb1171d318..e60407f9bf8dd 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php @@ -7,6 +7,8 @@ namespace Magento\Analytics\Test\Unit\Model; use Magento\Analytics\Model\NotificationTime; +use Magento\Authorization\Model\UserContextInterface; +use Magento\Framework\Intl\DateTimeFactory; use Magento\Framework\FlagManager; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; @@ -20,57 +22,105 @@ class NotificationTimeTest extends \PHPUnit\Framework\TestCase */ private $flagManagerMock; + /** + * @var UserContextInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $userContextInterfaceMock; + + /** + * @var DateTimeFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $dateTimeFactoryMock; + + /** + * @var \DateTime|\PHPUnit_Framework_MockObject_MockObject + */ + private $dateTimeMock; + /** * @var NotificationTime */ private $notificationTime; + /** + * @var int + */ + private $value; + + /** + * @var int + */ + private $userId; + public function setUp() { + $this->value = 10005000; + $this->userId = 1; + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) ->disableOriginalConstructor() ->getMock(); - + $this->userContextInterfaceMock = $this->getMockBuilder(UserContextInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->dateTimeFactoryMock = $this->getMockBuilder(DateTimeFactory::class) + ->getMock(); + $this->dateTimeMock = $this->getMockBuilder(\DateTime::class) + ->getMock(); $objectManagerHelper = new ObjectManagerHelper($this); $this->notificationTime = $objectManagerHelper->getObject( NotificationTime::class, [ 'flagManager' => $this->flagManagerMock, + 'userContext' => $this->userContextInterfaceMock, + 'dateTimeFactory' => $this->dateTimeFactoryMock ] ); } - public function testStoreLastTimeNotification() + public function testStoreLastTimeNotificationForCurrentUser() { - $value = 100500; + $this->userContextInterfaceMock->expects($this->once()) + ->method("getUserId") + ->willReturn(1); + $this->dateTimeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->dateTimeMock); + $this->dateTimeMock->expects($this->once()) + ->method('getTimestamp') + ->willReturn(10005000); $this->flagManagerMock ->expects($this->once()) ->method('saveFlag') - ->with(NotificationTime::NOTIFICATION_TIME, $value) + ->with(NotificationTime::NOTIFICATION_TIME . $this->userId, $this->value) ->willReturn(true); - $this->assertTrue($this->notificationTime->storeLastTimeNotification($value)); + $this->assertTrue($this->notificationTime->storeLastTimeNotificationForCurrentUser()); } - public function testGetLastTimeNotification() + public function testGetLastTimeNotificationForCurrentUser() { - $value = 100500; - + $this->userContextInterfaceMock->expects($this->once()) + ->method("getUserId") + ->willReturn(1); $this->flagManagerMock ->expects($this->once()) ->method('getFlagData') - ->with(NotificationTime::NOTIFICATION_TIME) + ->with(NotificationTime::NOTIFICATION_TIME . $this->userId) ->willReturn(true); - $this->assertEquals($value, $this->notificationTime->getLastTimeNotification()); + $this->assertEquals($this->value, $this->notificationTime->getLastTimeNotificationForCurrentUser()); } - public function testUnsetLastTimeNotificationValue() + public function testUnsetLastTimeNotificationValueForCurrentUser() { + $this->userContextInterfaceMock->expects($this->once()) + ->method("getUserId") + ->willReturn(1); $this->flagManagerMock ->expects($this->once()) ->method('deleteFlag') - ->with(NotificationTime::NOTIFICATION_TIME) + ->with(NotificationTime::NOTIFICATION_TIME . $this->userId) ->willReturn(true); - $this->assertTrue($this->notificationTime->unsetLastTimeNotificationValue()); + $this->assertTrue($this->notificationTime->unsetLastTimeNotificationValueForCurrentUser()); } } diff --git a/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml b/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml index 42cf4f937958b..3bfb5ca595790 100644 --- a/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml +++ b/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml @@ -9,7 +9,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> - + - -
- - - analytics_subscription_form.analytics_subscription_form_data_source - - Analytics Subscription - templates/form/collapsible - - - analytics_subscription_form - true - simple - data - - analytics_subscription_form.analytics_subscription_form_data_source - - - - - - - - - - - - - Magento_Ui/js/form/provider - - - - - - - - - false - - - - - - - actionCancel - true - - - - - - - - - - -
- - - - - - - advanced-reports-subscription-text - 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.

]]> -
-
-
-
- - - - - - - - - - - - - 1 - - - - - true - - analytics_subscription_checkbox - - - - - - Learn more.]]> - - 1 - 0 - - - - - - -
-
- - - actionCancel - - - - - - - - - - - - - - - advanced-reports-subscription-text - 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/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml b/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml new file mode 100644 index 0000000000000..c26b4e15dfe17 --- /dev/null +++ b/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml @@ -0,0 +1,98 @@ + + +
+ + + analytics_subscription_notification.analytics_subscription_notification_data_source + + Analytics Subscription + templates/form/collapsible + + + analytics_subscription_notification + true + simple + data + + analytics_subscription_notification.analytics_subscription_notification_data_source + + + + + + Magento_Ui/js/form/provider + + + + + + false + + + + + + + actionCancel + true + + + + + + + + + +
+ + + + + + + advanced-reports-subscription-text + Advanced Reporting + provides you with a dynamic suite of reports with rich insights about the health of your + business.


As part of the Advanced Reporting service, we may also use your customer + data for such purposes as benchmarking, improving our products and services, and providing you + with new and improved analytics.


By using Magento 2.2, you agree to the Advanced + Reporting Privacy Policy and Terms + of Service. You may opt out at any time from the Stores Configuration page.

]]> +
+
+
+
+ + + + + + + + +
+
+
diff --git a/app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js b/app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js deleted file mode 100644 index 9dee8d0c8e9ce..0000000000000 --- a/app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -define([ - 'jquery', - 'Magento_Ui/js/modal/modal-component', - 'Magento_Ui/js/modal/alert', - 'mage/translate' -], function ($, Modal, alert, $t) { - 'use strict'; - - return Modal.extend({ - defaults: { - postponeOptions: {}, - imports: { - postponeUrl: '${ $.provider }:postpone_url' - }, - modules: { - form: '${ $.parentName }' - } - }, - - /** - * Send request to postpone modal appearance for a certain time. - * - * @param {Object} options - additional request options. - */ - sendPostponeRequest: function (options) { - var self = this, - data = $.extend(this.form().source.data, options); - - $.ajax({ - type: 'POST', - url: this.postponeUrl, - data: data, - showLoader: true - }).done(function (xhr) { - if (xhr.error) { - self.onError(xhr); - } - }).fail(this.onError); - }, - - /** - * Error handler. - * - * @param {Object} xhr - request result. - */ - onError: function (xhr) { - if (xhr.statusText === 'abort') { - return; - } - - alert({ - content: xhr.message || $t('An error occurred while subscription process.') - }); - }, - - /** @inheritdoc */ - actionCancel: function () { - this.sendPostponeRequest(this.postponeOptions); - this.closeModal(); - } - }); -}); diff --git a/app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html b/app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html deleted file mode 100644 index 784e16d72c3f5..0000000000000 --- a/app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html +++ /dev/null @@ -1,13 +0,0 @@ - -
- - -
- -
-
diff --git a/app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html b/app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html deleted file mode 100644 index 297867c60c1e4..0000000000000 --- a/app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html +++ /dev/null @@ -1,17 +0,0 @@ - -
- - -
diff --git a/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less index 85454effcbd67..cb01cb5fbcda9 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less @@ -18,157 +18,108 @@ // _____________________________________________ .dashboard-advanced-reports { - .lib-vendor-prefix-display(flex); - border-color: @color-gray89; - border-style: solid; - border-width: 1px 0; - margin-bottom: @indent__l; - padding: @indent__m 0; + .lib-vendor-prefix-display(flex); + border-color: @color-gray89; + border-style: solid; + border-width: 1px 0; + margin-bottom: @indent__l; + padding: @indent__m 0; } .dashboard-advanced-reports-title { - &:extend(.dashboard-item-title all); - margin-bottom: @indent__s; + &:extend(.dashboard-item-title all); + margin-bottom: @indent__s; } .dashboard-advanced-reports-content { - line-height: @line-height__xl; + line-height: @line-height__xl; } .dashboard-advanced-reports-actions { - .lib-vendor-prefix-flex-basis(auto); - .lib-vendor-prefix-flex-grow(1); - .lib-vendor-prefix-flex-shrink(1); - align-self: center; - margin-left: @indent__m; - margin-right: @page-main-actions__padding; - text-align: right; + .lib-vendor-prefix-flex-basis(auto); + .lib-vendor-prefix-flex-grow(1); + .lib-vendor-prefix-flex-shrink(1); + align-self: center; + margin-left: @indent__m; + margin-right: @page-main-actions__padding; + text-align: right; } .action-advanced-reports { - &:extend(.abs-action-l all); - &:extend(.abs-action-pattern all); - background-color: @button-advanced-reports__background-color; - border-color: @button-advanced-reports__background-color; - color: @button-advanced-reports__color; - text-shadow: 1px 1px 0 rgba(0, 0, 0, .25); - white-space: nowrap; - - &:after { - &:extend(.abs-icon all); - content: @icon-external-link__content; - font-size: @font-size__xs; - vertical-align: super; - } + &:extend(.abs-action-l all); + &:extend(.abs-action-pattern all); + background-color: @button-advanced-reports__background-color; + border-color: @button-advanced-reports__background-color; + color: @button-advanced-reports__color; + text-shadow: 1px 1px 0 rgba(0, 0, 0, .25); + white-space: nowrap; + + &:after { + &:extend(.abs-icon all); + content: @icon-external-link__content; + font-size: @font-size__xs; + vertical-align: super; + } - &:hover, - &:active, - &:focus { - background-color: @button-advanced-reports__hover__background-color; - border-color: @button-advanced-reports__hover__border-color; - box-shadow: @button__hover__box-shadow; - color: @button-advanced-reports__color; - text-decoration: none; - } + &:hover, + &:active, + &:focus { + background-color: @button-advanced-reports__hover__background-color; + border-color: @button-advanced-reports__hover__border-color; + box-shadow: @button__hover__box-shadow; + color: @button-advanced-reports__color; + text-decoration: none; + } - &.disabled, - &[disabled] { - cursor: default; - opacity: @disabled__opacity; - pointer-events: none; - } + &.disabled, + &[disabled] { + cursor: default; + opacity: @disabled__opacity; + pointer-events: none; + } } // // Modal on dashboard // --------------------------------------------- -.advanced-reports-decline-subscription-modal, .advanced-reports-subscription-modal { - .modal-inner-wrap { - max-width: 80rem; - } -} + .modal-inner-wrap { + max-width: 75rem; + margin-top: 13rem; -.advanced-reports-subscription-modal { - .admin__fieldset { - padding: 0; - } -} + .modal-content, .modal-header { + padding-left: 4rem; + padding-right: 4rem; -.advanced-reports-decline-subscription-modal { - .advanced-reports-subscription-text { - margin-bottom: 0; + .action-close { + display: none; + } } + } - .modal-content { - padding-bottom: 0; - } + .admin__fieldset { + padding: 0; + } } .advanced-reports-subscription-text { - line-height: @line-height__xl; - - .list { - .lib-list-reset-styles(@_margin: @indent__m 0, @_padding: 0); - - li { - padding-left: @indent__l; - position: relative; - - &:before { - content: '\2022'; - left: 1rem; - position: absolute; - } - - + li { - margin-top: @indent__m; - } - } - } + line-height: @line-height__xl; + padding-bottom: 8rem; } -.advanced-reports-subscription-actions { - font-size: 0; - text-align: justify; - - &:after { - content: ''; - display: inline-block; - height: 0; - overflow: hidden; - visibility: hidden; - width: 100%; - } - - .action-basic, - .action-additional { - &:extend(.abs-action-l all); - } - - .advanced-reports-subscription-postpone, - .advanced-reports-subscription-disable, - .advanced-reports-subscription-enable { - display: inline-block; - vertical-align: top; - } +.advanced-reports-subscription-close { + display: inline-block; + vertical-align: top; + float: right; } -.advanced-reports-subscription-enable { - .admin__field { - max-width: 22rem; - } - - .admin__field-label { - font-size: @font-size__s; - line-height: @line-height__l; - } - - .action-basic { - &:extend(.abs-action-primary all); - margin-bottom: @indent__s; - } +.advanced-reports-subscription-modal { + h1:first-of-type { + background: url("Magento_Analytics::images/advanced-reporting-badge.svg") no-repeat; + background-size: 44px 50px; + padding: 1.3rem 0 2rem 6rem; + } } // diff --git a/app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/advanced-reporting-badge.svg b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/advanced-reporting-badge.svg new file mode 100644 index 0000000000000..5abae13c5fa99 --- /dev/null +++ b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/advanced-reporting-badge.svg @@ -0,0 +1,7 @@ + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php index 0cbb853167f30..e362d51790a76 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php @@ -14,76 +14,11 @@ class SubscriptionBlock extends Modal { /** - * Modal checkbox + * Close subscription pop-up button * * @var string */ - private $checkbox = '[name="analytics_subscription_checkbox"]'; - - /** - * Enable Advanced Reporting button - * - * @var string - */ - private $acceptReportingButton = '[data-index="analytics_subscription_button_accept"]'; - - /** - * Disable Advanced Reporting button - * - * @var string - */ - private $declineReportingButton = '[data-index="analytics_subscription_button_decline"]'; - - /** - * Skip subscription pop-up button - * - * @var string - */ - private $skipReportingButton = '[data-index="analytics_subscription_button_postpone"]'; - - /** - * Enable checkbox in modal window. - * - * @return void - */ - public function enableCheckbox() - { - $this->_rootElement->find($this->checkbox, Locator::SELECTOR_CSS, 'checkbox')->setValue('Yes'); - } - - /** - * Disable checkbox in modal window. - * - * @return void - */ - public function disableCheckbox() - { - $this->_rootElement->find($this->checkbox, Locator::SELECTOR_CSS, 'checkbox')->setValue('No'); - } - - /** - * Enable Advanced Reporting on a subscription popup. - * - * @return void - */ - public function acceptAdvancedReporting() - { - $this->waitModalAnimationFinished(); - $this->_rootElement->find($this->acceptReportingButton)->click(); - $this->waitForElementNotVisible($this->loadingMask); - } - - /** - * Disable Advanced Reporting on a subscription popup. - * - * @return void - */ - public function declineAdvancedReporting() - { - $this->waitModalAnimationFinished(); - $this->_rootElement->find($this->declineReportingButton)->click(); - $this->waitForElementNotVisible($this->loadingMask); - } + private $closeReportingButton = '[data-index="analytics_subscription_button_close"]'; /** * Skip subscription popup. @@ -93,7 +28,7 @@ public function declineAdvancedReporting() public function skipAdvancedReporting() { $this->waitModalAnimationFinished(); - $this->_rootElement->find($this->skipReportingButton)->click(); + $this->_rootElement->find($this->closeReportingButton)->click(); $this->waitForElementNotVisible($this->loadingMask); } } From 8598aa6fef44d52805428402282f78f122a0ab86 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 4 Oct 2017 16:02:48 -0500 Subject: [PATCH 012/194] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- app/code/Magento/Analytics/etc/di.xml | 5 ----- app/code/Magento/Analytics/etc/module.xml | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/code/Magento/Analytics/etc/di.xml b/app/code/Magento/Analytics/etc/di.xml index 09efd7c36ad83..56657b58475d3 100644 --- a/app/code/Magento/Analytics/etc/di.xml +++ b/app/code/Magento/Analytics/etc/di.xml @@ -23,11 +23,6 @@ - - - Magento\Config\Model\ResourceModel\Config\Data - - diff --git a/app/code/Magento/Analytics/etc/module.xml b/app/code/Magento/Analytics/etc/module.xml index 32ee5d23a4d86..b78ecc9256ffb 100644 --- a/app/code/Magento/Analytics/etc/module.xml +++ b/app/code/Magento/Analytics/etc/module.xml @@ -12,6 +12,7 @@ + From 54c029c455319d2fc2f454f19c7fab798a010d9e Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 4 Oct 2017 16:04:45 -0500 Subject: [PATCH 013/194] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- app/code/Magento/Analytics/etc/module.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Analytics/etc/module.xml b/app/code/Magento/Analytics/etc/module.xml index b78ecc9256ffb..37d1a9e79ad70 100644 --- a/app/code/Magento/Analytics/etc/module.xml +++ b/app/code/Magento/Analytics/etc/module.xml @@ -12,7 +12,7 @@ - + From e1d437a70f0429a8c24711f48d3eeb29b786a47b Mon Sep 17 00:00:00 2001 From: aakimov Date: Thu, 5 Oct 2017 12:11:07 +0300 Subject: [PATCH 014/194] MAGETWO-80203: [2.2.x] Asymmetric Transaction Error with ElasticSearch --- app/code/Magento/Catalog/Model/Product/Gallery/Processor.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php b/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php index 977d93f350145..31e322f4e38f2 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php @@ -192,6 +192,7 @@ public function addImage( $mediaGalleryData['images'][] = [ 'file' => $fileName, 'position' => $position, + 'media_type' => 'image', 'label' => '', 'disabled' => (int)$exclude, ]; From 378ea5073184b233153c14ed4ec3ba4b964245d7 Mon Sep 17 00:00:00 2001 From: Joan He Date: Thu, 5 Oct 2017 10:49:20 -0500 Subject: [PATCH 015/194] MAGETWO-80488: Apply AR code from previous development - remove @since annotation in Analytics module --- .../Analytics/Api/Data/LinkInterface.php | 3 -- .../Analytics/Api/LinkProviderInterface.php | 2 -- .../System/Config/AdditionalComment.php | 3 -- .../System/Config/CollectionTimeLabel.php | 2 -- .../System/Config/SubscriptionStatusLabel.php | 5 ---- .../Adminhtml/System/Config/Vertical.php | 3 -- .../Adminhtml/BIEssentials/SignUp.php | 6 ---- .../Controller/Adminhtml/Reports/Show.php | 5 ---- .../Adminhtml/Subscription/Retry.php | 5 ---- .../Magento/Analytics/Cron/CollectData.php | 5 ---- app/code/Magento/Analytics/Cron/SignUp.php | 8 ----- app/code/Magento/Analytics/Cron/Update.php | 8 ----- .../Analytics/Model/AnalyticsToken.php | 9 ------ .../Model/Condition/CanViewNotification.php | 5 ---- app/code/Magento/Analytics/Model/Config.php | 4 --- .../Baseurl/SubscriptionUpdateHandler.php | 9 ------ .../Model/Config/Backend/CollectionTime.php | 4 --- .../Model/Config/Backend/Enabled.php | 4 --- .../Backend/Enabled/SubscriptionHandler.php | 13 --------- .../Model/Config/Backend/Vertical.php | 2 -- .../Magento/Analytics/Model/Config/Mapper.php | 2 -- .../Magento/Analytics/Model/Config/Reader.php | 5 ---- .../Model/Config/Source/Vertical.php | 4 --- .../Analytics/Model/ConfigInterface.php | 2 -- .../Magento/Analytics/Model/Connector.php | 5 ---- .../Model/Connector/CommandInterface.php | 2 -- .../Model/Connector/Http/Client/Curl.php | 8 ----- .../Model/Connector/Http/ClientInterface.php | 2 -- .../Connector/Http/ConverterInterface.php | 4 --- .../Model/Connector/Http/JsonConverter.php | 4 --- .../Model/Connector/Http/ResponseFactory.php | 2 -- .../Http/ResponseHandlerInterface.php | 2 -- .../Model/Connector/Http/ResponseResolver.php | 5 ---- .../Connector/NotifyDataChangedCommand.php | 9 ------ .../Analytics/Model/Connector/OTPRequest.php | 9 ------ .../Model/Connector/ResponseHandler/OTP.php | 2 -- .../Connector/ResponseHandler/ReSignUp.php | 6 ---- .../Connector/ResponseHandler/SignUp.php | 5 ---- .../Connector/ResponseHandler/Update.php | 2 -- .../Model/Connector/SignUpCommand.php | 10 ------- .../Model/Connector/UpdateCommand.php | 10 ------- .../Magento/Analytics/Model/Cryptographer.php | 10 ------- .../Analytics/Model/EncodedContext.php | 6 ---- .../State/SubscriptionUpdateException.php | 1 - .../Analytics/Model/ExportDataHandler.php | 16 ---------- .../Model/ExportDataHandlerInterface.php | 2 -- .../Model/ExportDataHandlerNotification.php | 5 ---- app/code/Magento/Analytics/Model/FileInfo.php | 6 ---- .../Analytics/Model/FileInfoManager.php | 10 ------- .../Magento/Analytics/Model/FileRecorder.php | 11 ------- .../Analytics/Model/IntegrationManager.php | 9 ------ app/code/Magento/Analytics/Model/Link.php | 6 ---- .../Magento/Analytics/Model/LinkProvider.php | 8 ----- .../Analytics/Model/NotificationTime.php | 8 ----- .../Model/Plugin/BaseUrlConfigPlugin.php | 5 ---- .../Analytics/Model/ProviderFactory.php | 4 --- .../Analytics/Model/ReportUrlProvider.php | 8 ----- .../Magento/Analytics/Model/ReportWriter.php | 7 ----- .../Analytics/Model/ReportWriterInterface.php | 2 -- .../Model/ReportXml/ModuleIterator.php | 4 --- .../Model/StoreConfigurationProvider.php | 7 ----- .../Model/SubscriptionStatusProvider.php | 8 ----- .../NotificationAboutFailedSubscription.php | 8 ----- .../Magento/Analytics/ReportXml/Config.php | 4 --- .../ReportXml/Config/Converter/Xml.php | 3 -- .../Analytics/ReportXml/Config/Mapper.php | 2 -- .../Analytics/ReportXml/Config/Reader.php | 5 ---- .../Analytics/ReportXml/ConfigInterface.php | 2 -- .../Analytics/ReportXml/ConnectionFactory.php | 5 ---- .../DB/Assembler/AssemblerInterface.php | 2 -- .../DB/Assembler/FilterAssembler.php | 5 ---- .../ReportXml/DB/Assembler/FromAssembler.php | 6 ---- .../ReportXml/DB/Assembler/JoinAssembler.php | 7 ----- .../ReportXml/DB/ColumnsResolver.php | 7 ----- .../ReportXml/DB/ConditionResolver.php | 9 ------ .../Analytics/ReportXml/DB/NameResolver.php | 3 -- .../ReportXml/DB/ReportValidator.php | 5 ---- .../Analytics/ReportXml/DB/SelectBuilder.php | 29 ------------------- .../ReportXml/DB/SelectBuilderFactory.php | 4 --- .../Analytics/ReportXml/IteratorFactory.php | 5 ---- .../Magento/Analytics/ReportXml/Query.php | 9 ------ .../Analytics/ReportXml/QueryFactory.php | 11 ------- .../Analytics/ReportXml/ReportProvider.php | 7 ----- .../Analytics/ReportXml/SelectHydrator.php | 10 ------- .../Magento/Analytics/Setup/InstallData.php | 2 -- .../Ui/DataProvider/DummyDataProvider.php | 22 -------------- 86 files changed, 520 deletions(-) diff --git a/app/code/Magento/Analytics/Api/Data/LinkInterface.php b/app/code/Magento/Analytics/Api/Data/LinkInterface.php index f2b1ec579c4ab..6597dff868b9f 100644 --- a/app/code/Magento/Analytics/Api/Data/LinkInterface.php +++ b/app/code/Magento/Analytics/Api/Data/LinkInterface.php @@ -9,19 +9,16 @@ * Interface LinkInterface * * Represents link with collected data and initialized vector for decryption. - * @since 2.2.0 */ interface LinkInterface { /** * @return string - * @since 2.2.0 */ public function getUrl(); /** * @return string - * @since 2.2.0 */ public function getInitializationVector(); } diff --git a/app/code/Magento/Analytics/Api/LinkProviderInterface.php b/app/code/Magento/Analytics/Api/LinkProviderInterface.php index 54b21ed731e3d..6ee43a423337e 100644 --- a/app/code/Magento/Analytics/Api/LinkProviderInterface.php +++ b/app/code/Magento/Analytics/Api/LinkProviderInterface.php @@ -7,13 +7,11 @@ /** * Provides link to file with collected report data. - * @since 2.2.0 */ interface LinkProviderInterface { /** * @return \Magento\Analytics\Api\Data\LinkInterface - * @since 2.2.0 */ public function get(); } diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/AdditionalComment.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/AdditionalComment.php index 9f450b9b6936d..c66996d839c09 100644 --- a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/AdditionalComment.php +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/AdditionalComment.php @@ -7,14 +7,12 @@ /** * Provides field with additional information - * @since 2.2.0 */ class AdditionalComment extends \Magento\Config\Block\System\Config\Form\Field { /** * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @return string - * @since 2.2.0 */ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) { @@ -27,7 +25,6 @@ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $ele * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @param string $html * @return string - * @since 2.2.0 */ private function decorateRowHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element, $html) { diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php index 9e19a9e6c2388..c4118792255cd 100644 --- a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php @@ -7,7 +7,6 @@ /** * Provides label with default Time Zone - * @since 2.2.0 */ class CollectionTimeLabel extends \Magento\Config\Block\System\Config\Form\Field { @@ -16,7 +15,6 @@ class CollectionTimeLabel extends \Magento\Config\Block\System\Config\Form\Field * * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @return string - * @since 2.2.0 */ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) { diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php index bfdee16707618..c09213c7f009d 100644 --- a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php @@ -13,13 +13,11 @@ * * Provides labels for subscription status * Status can be reviewed in System Configuration - * @since 2.2.0 */ class SubscriptionStatusLabel extends \Magento\Config\Block\System\Config\Form\Field { /** * @var SubscriptionStatusProvider - * @since 2.2.0 */ private $subscriptionStatusProvider; @@ -29,7 +27,6 @@ class SubscriptionStatusLabel extends \Magento\Config\Block\System\Config\Form\F * @param Context $context * @param SubscriptionStatusProvider $labelStatusProvider * @param array $data - * @since 2.2.0 */ public function __construct( Context $context, @@ -45,7 +42,6 @@ public function __construct( * * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @return string - * @since 2.2.0 */ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) { @@ -60,7 +56,6 @@ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $ele * Prepare label for subscription status * * @return string - * @since 2.2.0 */ private function prepareLabelValue() { diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php index be3d8eabc899b..b7ec114e69563 100644 --- a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php @@ -7,14 +7,12 @@ /** * Provides select with industry information - * @since 2.2.2 */ class Vertical extends \Magento\Config\Block\System\Config\Form\Field { /** * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @return string - * @since 2.2.2 */ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) { @@ -27,7 +25,6 @@ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $ele * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @param string $html * @return string - * @since 2.2.2 */ private function decorateRowHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element, $html) { diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php b/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php index 4cbfa639d23b4..a90a971cf41b4 100644 --- a/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php +++ b/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php @@ -13,7 +13,6 @@ * Class SignUp * * Provides link to BI Essentials signup - * @since 2.2.0 */ class SignUp extends Action { @@ -21,20 +20,17 @@ class SignUp extends Action * Path to config value with URL to BI Essentials sign-up page. * * @var string - * @since 2.2.0 */ private $urlBIEssentialsConfigPath = 'analytics/url/bi_essentials'; /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $config; /** * @param Context $context * @param ScopeConfigInterface $config - * @since 2.2.0 */ public function __construct( Context $context, @@ -48,7 +44,6 @@ public function __construct( * Check admin permissions for this controller * * @return boolean - * @since 2.2.0 */ protected function _isAllowed() { @@ -59,7 +54,6 @@ protected function _isAllowed() * Provides link to BI Essentials signup * * @return \Magento\Framework\Controller\AbstractResult - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php b/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php index 5fb0085fee43d..1b0e5c92420de 100644 --- a/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php +++ b/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php @@ -15,20 +15,17 @@ /** * Provide redirect to resource with reports. - * @since 2.2.0 */ class Show extends Action { /** * @var ReportUrlProvider - * @since 2.2.0 */ private $reportUrlProvider; /** * @param Context $context * @param ReportUrlProvider $reportUrlProvider - * @since 2.2.0 */ public function __construct( Context $context, @@ -42,7 +39,6 @@ public function __construct( * Check admin permissions for this controller. * * @return boolean - * @since 2.2.0 */ protected function _isAllowed() { @@ -53,7 +49,6 @@ protected function _isAllowed() * Redirect to resource with reports. * * @return Redirect $resultRedirect - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php index 85d34e83f0c9f..122cf74123cc9 100644 --- a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php +++ b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php @@ -15,7 +15,6 @@ /** * Retry subscription to Magento BI Advanced Reporting. - * @since 2.2.0 */ class Retry extends Action { @@ -23,14 +22,12 @@ class Retry extends Action * Resource for managing subscription to Magento Analytics. * * @var SubscriptionHandler - * @since 2.2.0 */ private $subscriptionHandler; /** * @param Context $context * @param SubscriptionHandler $subscriptionHandler - * @since 2.2.0 */ public function __construct( Context $context, @@ -44,7 +41,6 @@ public function __construct( * Check admin permissions for this controller * * @return boolean - * @since 2.2.0 */ protected function _isAllowed() { @@ -55,7 +51,6 @@ protected function _isAllowed() * Retry process of subscription. * * @return Redirect - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Cron/CollectData.php b/app/code/Magento/Analytics/Cron/CollectData.php index d11ade9a812ff..ff0b3e4f67638 100644 --- a/app/code/Magento/Analytics/Cron/CollectData.php +++ b/app/code/Magento/Analytics/Cron/CollectData.php @@ -10,7 +10,6 @@ /** * Cron for data collection by a schedule for MBI. - * @since 2.2.0 */ class CollectData { @@ -18,7 +17,6 @@ class CollectData * Resource for the handling of a new data collection. * * @var ExportDataHandlerInterface - * @since 2.2.0 */ private $exportDataHandler; @@ -26,14 +24,12 @@ class CollectData * Resource which provides a status of subscription. * * @var SubscriptionStatusProvider - * @since 2.2.0 */ private $subscriptionStatus; /** * @param ExportDataHandlerInterface $exportDataHandler * @param SubscriptionStatusProvider $subscriptionStatus - * @since 2.2.0 */ public function __construct( ExportDataHandlerInterface $exportDataHandler, @@ -45,7 +41,6 @@ public function __construct( /** * @return bool - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Cron/SignUp.php b/app/code/Magento/Analytics/Cron/SignUp.php index cc5c84e93a6d9..c17b9b8c381c3 100644 --- a/app/code/Magento/Analytics/Cron/SignUp.php +++ b/app/code/Magento/Analytics/Cron/SignUp.php @@ -13,25 +13,21 @@ /** * Class SignUp - * @since 2.2.0 */ class SignUp { /** * @var Connector - * @since 2.2.0 */ private $connector; /** * @var WriterInterface - * @since 2.2.0 */ private $configWriter; /** * @var FlagManager - * @since 2.2.0 */ private $flagManager; @@ -39,7 +35,6 @@ class SignUp * Reinitable Config Model. * * @var ReinitableConfigInterface - * @since 2.2.0 */ private $reinitableConfig; @@ -48,7 +43,6 @@ class SignUp * @param WriterInterface $configWriter * @param FlagManager $flagManager * @param ReinitableConfigInterface $reinitableConfig - * @since 2.2.0 */ public function __construct( Connector $connector, @@ -67,7 +61,6 @@ public function __construct( * In case of failure writes message to notifications inbox * * @return bool - * @since 2.2.0 */ public function execute() { @@ -98,7 +91,6 @@ public function execute() * re-initialize config cache to avoid auto-generate new schedule items. * * @return bool - * @since 2.2.0 */ private function deleteAnalyticsCronExpr() { diff --git a/app/code/Magento/Analytics/Cron/Update.php b/app/code/Magento/Analytics/Cron/Update.php index 89a2496e088c1..9062a7bac7551 100644 --- a/app/code/Magento/Analytics/Cron/Update.php +++ b/app/code/Magento/Analytics/Cron/Update.php @@ -14,37 +14,31 @@ /** * Executes by cron schedule in case base url was changed - * @since 2.2.0 */ class Update { /** * @var Connector - * @since 2.2.0 */ private $connector; /** * @var WriterInterface - * @since 2.2.0 */ private $configWriter; /** * @var ReinitableConfigInterface - * @since 2.2.0 */ private $reinitableConfig; /** * @var FlagManager - * @since 2.2.0 */ private $flagManager; /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; @@ -54,7 +48,6 @@ class Update * @param ReinitableConfigInterface $reinitableConfig * @param FlagManager $flagManager * @param AnalyticsToken $analyticsToken - * @since 2.2.0 */ public function __construct( Connector $connector, @@ -74,7 +67,6 @@ public function __construct( * Execute scheduled update operation * * @return bool - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Model/AnalyticsToken.php b/app/code/Magento/Analytics/Model/AnalyticsToken.php index 58ef45b4f4279..ccec4d1bbe958 100644 --- a/app/code/Magento/Analytics/Model/AnalyticsToken.php +++ b/app/code/Magento/Analytics/Model/AnalyticsToken.php @@ -11,13 +11,11 @@ /** * Model for handling Magento BI token value into config. - * @since 2.2.0 */ class AnalyticsToken { /** * Path to value of Magento BI token into config. - * @since 2.2.0 */ private $tokenPath = 'analytics/general/token'; @@ -25,7 +23,6 @@ class AnalyticsToken * Reinitable Config Model. * * @var ReinitableConfigInterface - * @since 2.2.0 */ private $reinitableConfig; @@ -33,7 +30,6 @@ class AnalyticsToken * Scope config model. * * @var ScopeConfigInterface - * @since 2.2.0 */ private $config; @@ -41,7 +37,6 @@ class AnalyticsToken * Service which allows to write values into config. * * @var WriterInterface - * @since 2.2.0 */ private $configWriter; @@ -49,7 +44,6 @@ class AnalyticsToken * @param ReinitableConfigInterface $reinitableConfig * @param ScopeConfigInterface $config * @param WriterInterface $configWriter - * @since 2.2.0 */ public function __construct( ReinitableConfigInterface $reinitableConfig, @@ -65,7 +59,6 @@ public function __construct( * Get Magento BI token value. * * @return string|null - * @since 2.2.0 */ public function getToken() { @@ -78,7 +71,6 @@ public function getToken() * @param string $value * * @return bool - * @since 2.2.0 */ public function storeToken($value) { @@ -92,7 +84,6 @@ public function storeToken($value) * Check Magento BI token value exist. * * @return bool - * @since 2.2.0 */ public function isTokenExist() { diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php index 157a033959c42..88bc50e622f01 100644 --- a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -13,7 +13,6 @@ * * Dynamic validator for UI analytics notification, manage UI component visibility. * Return true if the logged in user has not seen the notification. - * @since 2.2.2 */ class CanViewNotification implements VisibilityConditionInterface { @@ -24,7 +23,6 @@ class CanViewNotification implements VisibilityConditionInterface /** * @var NotificationTime - * @since 2.2.2 */ private $notificationTime; @@ -32,7 +30,6 @@ class CanViewNotification implements VisibilityConditionInterface * CanViewNotification constructor. * * @param NotificationTime $notificationTime - * @since 2.2.2 */ public function __construct( NotificationTime $notificationTime @@ -44,7 +41,6 @@ public function __construct( * Validate if notification popup can be shown * * @inheritdoc - * @since 2.2.2 */ public function isVisible(array $arguments) { @@ -59,7 +55,6 @@ public function isVisible(array $arguments) /** * @return string - * @since 2.2.2 */ public function getName() { diff --git a/app/code/Magento/Analytics/Model/Config.php b/app/code/Magento/Analytics/Model/Config.php index 140d7130260a2..ba508187b4b9f 100644 --- a/app/code/Magento/Analytics/Model/Config.php +++ b/app/code/Magento/Analytics/Model/Config.php @@ -10,19 +10,16 @@ /** * Config of Analytics. - * @since 2.2.0 */ class Config implements ConfigInterface { /** * @var DataInterface - * @since 2.2.0 */ private $data; /** * @param DataInterface $data - * @since 2.2.0 */ public function __construct(DataInterface $data) { @@ -35,7 +32,6 @@ public function __construct(DataInterface $data) * @param string|null $key * @param string|null $default * @return array - * @since 2.2.0 */ public function get($key = null, $default = null) { diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php b/app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php index f9fa38fe7f5fb..6e6f008d49f7e 100644 --- a/app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php +++ b/app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php @@ -13,7 +13,6 @@ /** * Class for processing of change of Base URL. - * @since 2.2.0 */ class SubscriptionUpdateHandler { @@ -36,13 +35,11 @@ class SubscriptionUpdateHandler * Max value for a reserve counter to update subscription. * * @var int - * @since 2.2.0 */ private $attemptsInitValue = 48; /** * @var WriterInterface - * @since 2.2.0 */ private $configWriter; @@ -50,25 +47,21 @@ class SubscriptionUpdateHandler * Cron expression for a update handler. * * @var string - * @since 2.2.0 */ private $cronExpression = '0 * * * *'; /** * @var FlagManager - * @since 2.2.0 */ private $flagManager; /** * @var ReinitableConfigInterface - * @since 2.2.0 */ private $reinitableConfig; /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; @@ -77,7 +70,6 @@ class SubscriptionUpdateHandler * @param FlagManager $flagManager * @param ReinitableConfigInterface $reinitableConfig * @param WriterInterface $configWriter - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -96,7 +88,6 @@ public function __construct( * * @param string $url * @return bool - * @since 2.2.0 */ public function processUrlUpdate(string $url) { diff --git a/app/code/Magento/Analytics/Model/Config/Backend/CollectionTime.php b/app/code/Magento/Analytics/Model/Config/Backend/CollectionTime.php index beb6f9d79f7ab..e26ad01fc74bf 100644 --- a/app/code/Magento/Analytics/Model/Config/Backend/CollectionTime.php +++ b/app/code/Magento/Analytics/Model/Config/Backend/CollectionTime.php @@ -17,7 +17,6 @@ /** * Config value backend model. - * @since 2.2.0 */ class CollectionTime extends Value { @@ -28,7 +27,6 @@ class CollectionTime extends Value /** * @var WriterInterface - * @since 2.2.0 */ private $configWriter; @@ -41,7 +39,6 @@ class CollectionTime extends Value * @param AbstractResource|null $resource * @param AbstractDb|null $resourceCollection * @param array $data - * @since 2.2.0 */ public function __construct( Context $context, @@ -63,7 +60,6 @@ public function __construct( * {@inheritdoc}. Set schedule setting for cron. * * @return Value - * @since 2.2.0 */ public function afterSave() { diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php b/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php index 5544cd0df9454..ac97f2a843e61 100644 --- a/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php +++ b/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php @@ -17,7 +17,6 @@ /** * Config value backend model. - * @since 2.2.0 */ class Enabled extends Value { @@ -30,7 +29,6 @@ class Enabled extends Value * Service for processing of activation/deactivation MBI subscription. * * @var SubscriptionHandler - * @since 2.2.0 */ private $subscriptionHandler; @@ -43,7 +41,6 @@ class Enabled extends Value * @param AbstractResource|null $resource * @param AbstractDb|null $resourceCollection * @param array $data - * @since 2.2.0 */ public function __construct( Context $context, @@ -64,7 +61,6 @@ public function __construct( * * @return Value * @throws LocalizedException - * @since 2.2.0 */ public function afterSave() { diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php index 04202cdcda11c..4b125949948c6 100644 --- a/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php +++ b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php @@ -13,7 +13,6 @@ /** * Class for processing of activation/deactivation MBI subscription. - * @since 2.2.0 */ class SubscriptionHandler { @@ -42,7 +41,6 @@ class SubscriptionHandler * Max value for reserve counter of attempts to subscribe. * * @var int - * @since 2.2.0 */ private $attemptsInitValue = 24; @@ -50,7 +48,6 @@ class SubscriptionHandler * Service which allows to write values into config. * * @var WriterInterface - * @since 2.2.0 */ private $configWriter; @@ -58,7 +55,6 @@ class SubscriptionHandler * Flag Manager. * * @var FlagManager - * @since 2.2.0 */ private $flagManager; @@ -66,13 +62,11 @@ class SubscriptionHandler * Model for handling Magento BI token value. * * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var ReinitableConfigInterface - * @since 2.2.0 */ private $reinitableConfig; @@ -81,7 +75,6 @@ class SubscriptionHandler * @param FlagManager $flagManager * @param AnalyticsToken $analyticsToken * @param ReinitableConfigInterface $reinitableConfig - * @since 2.2.0 */ public function __construct( WriterInterface $configWriter, @@ -101,7 +94,6 @@ public function __construct( * Activate process of subscription handling if Analytics token is not received. * * @return bool - * @since 2.2.0 */ public function processEnabled() { @@ -118,7 +110,6 @@ public function processEnabled() * Set cron schedule setting into config for activation of subscription process. * * @return bool - * @since 2.2.0 */ private function setCronSchedule() { @@ -130,7 +121,6 @@ private function setCronSchedule() * Set flag as reserve counter of attempts subscription operation. * * @return bool - * @since 2.2.0 */ private function setAttemptsFlag() { @@ -145,7 +135,6 @@ private function setAttemptsFlag() * and interrupt subscription handling if Analytics token is not received. * * @return bool - * @since 2.2.0 */ public function processDisabled() { @@ -162,7 +151,6 @@ public function processDisabled() * Unset flag of attempts subscription operation. * * @return bool - * @since 2.2.0 */ private function unsetAttemptsFlag() { @@ -174,7 +162,6 @@ private function unsetAttemptsFlag() * Unset schedule of collection data cron. * * @return bool - * @since 2.2.0 */ private function disableCollectionData() { diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Vertical.php b/app/code/Magento/Analytics/Model/Config/Backend/Vertical.php index 0fe9caa4ea0a0..1aabbb91ddf87 100644 --- a/app/code/Magento/Analytics/Model/Config/Backend/Vertical.php +++ b/app/code/Magento/Analytics/Model/Config/Backend/Vertical.php @@ -9,7 +9,6 @@ /** * A backend model for verticals configuration. - * @since 2.2.0 */ class Vertical extends \Magento\Framework\App\Config\Value { @@ -21,7 +20,6 @@ class Vertical extends \Magento\Framework\App\Config\Value * * @return $this * @throws LocalizedException if the value of the selected vertical is empty. - * @since 2.2.0 */ public function beforeSave() { diff --git a/app/code/Magento/Analytics/Model/Config/Mapper.php b/app/code/Magento/Analytics/Model/Config/Mapper.php index d672248777ec5..504690b8e4763 100644 --- a/app/code/Magento/Analytics/Model/Config/Mapper.php +++ b/app/code/Magento/Analytics/Model/Config/Mapper.php @@ -8,7 +8,6 @@ /** * Transforms Analytics configuration data. - * @since 2.2.0 */ class Mapper { @@ -35,7 +34,6 @@ class Mapper * ], * ] * ]; - * @since 2.2.0 */ public function execute($configData) { diff --git a/app/code/Magento/Analytics/Model/Config/Reader.php b/app/code/Magento/Analytics/Model/Config/Reader.php index e5e120f95bbd6..8980e31627717 100644 --- a/app/code/Magento/Analytics/Model/Config/Reader.php +++ b/app/code/Magento/Analytics/Model/Config/Reader.php @@ -9,26 +9,22 @@ /** * Composite reader for config. - * @since 2.2.0 */ class Reader implements ReaderInterface { /** * @var ReaderInterface[] - * @since 2.2.0 */ private $readers; /** * @var Mapper - * @since 2.2.0 */ private $mapper; /** * @param Mapper $mapper * @param ReaderInterface[] $readers - * @since 2.2.0 */ public function __construct( Mapper $mapper, @@ -43,7 +39,6 @@ public function __construct( * * @param string|null $scope * @return array - * @since 2.2.0 */ public function read($scope = null) { diff --git a/app/code/Magento/Analytics/Model/Config/Source/Vertical.php b/app/code/Magento/Analytics/Model/Config/Source/Vertical.php index 7aac0b070af4b..c9d9582ea7c7a 100644 --- a/app/code/Magento/Analytics/Model/Config/Source/Vertical.php +++ b/app/code/Magento/Analytics/Model/Config/Source/Vertical.php @@ -10,7 +10,6 @@ * * Prepares and provides options for a selector of verticals which is located * in the corresponding configuration menu of the Admin area. - * @since 2.2.0 */ class Vertical implements \Magento\Framework\Option\ArrayInterface { @@ -23,13 +22,11 @@ class Vertical implements \Magento\Framework\Option\ArrayInterface * It is supposed that the list may be changed in each Magento release. * * @var array - * @since 2.2.0 */ private $verticals; /** * @param array $verticals - * @since 2.2.0 */ public function __construct(array $verticals) { @@ -38,7 +35,6 @@ public function __construct(array $verticals) /** * {@inheritdoc} - * @since 2.2.0 */ public function toOptionArray() { diff --git a/app/code/Magento/Analytics/Model/ConfigInterface.php b/app/code/Magento/Analytics/Model/ConfigInterface.php index 2f84f9bffe8de..caaa2e100c1c7 100644 --- a/app/code/Magento/Analytics/Model/ConfigInterface.php +++ b/app/code/Magento/Analytics/Model/ConfigInterface.php @@ -8,7 +8,6 @@ /** * Interface for Analytics Config. - * @since 2.2.0 */ interface ConfigInterface { @@ -18,7 +17,6 @@ interface ConfigInterface * @param string|null $key * @param string|null $default * @return array - * @since 2.2.0 */ public function get($key = null, $default = null); } diff --git a/app/code/Magento/Analytics/Model/Connector.php b/app/code/Magento/Analytics/Model/Connector.php index 5b2fdb0af525b..23b0ffa213b6e 100644 --- a/app/code/Magento/Analytics/Model/Connector.php +++ b/app/code/Magento/Analytics/Model/Connector.php @@ -12,7 +12,6 @@ * A connector to external services. * * Aggregates and executes commands which perform requests to external services. - * @since 2.2.0 */ class Connector { @@ -24,20 +23,17 @@ class Connector * The list may be configured in each module via '/etc/di.xml'. * * @var string[] - * @since 2.2.0 */ private $commands; /** * @var ObjectManagerInterface - * @since 2.2.0 */ private $objectManager; /** * @param array $commands * @param ObjectManagerInterface $objectManager - * @since 2.2.0 */ public function __construct( array $commands, @@ -53,7 +49,6 @@ public function __construct( * @param string $commandName * @return bool * @throws NotFoundException if the command is not found. - * @since 2.2.0 */ public function execute($commandName) { diff --git a/app/code/Magento/Analytics/Model/Connector/CommandInterface.php b/app/code/Magento/Analytics/Model/Connector/CommandInterface.php index cf7fe4e24f721..7a8774fe3dba9 100644 --- a/app/code/Magento/Analytics/Model/Connector/CommandInterface.php +++ b/app/code/Magento/Analytics/Model/Connector/CommandInterface.php @@ -8,7 +8,6 @@ /** * Introduces family of integration calls. * Each implementation represents call to external service. - * @since 2.2.0 */ interface CommandInterface { @@ -17,7 +16,6 @@ interface CommandInterface * Information about destination and arguments appears from config * * @return bool - * @since 2.2.0 */ public function execute(); } diff --git a/app/code/Magento/Analytics/Model/Connector/Http/Client/Curl.php b/app/code/Magento/Analytics/Model/Connector/Http/Client/Curl.php index 0e7c6f24c2a52..c223bb1f3b07d 100644 --- a/app/code/Magento/Analytics/Model/Connector/Http/Client/Curl.php +++ b/app/code/Magento/Analytics/Model/Connector/Http/Client/Curl.php @@ -14,31 +14,26 @@ * A CURL HTTP client. * * Sends requests via a CURL adapter. - * @since 2.2.0 */ class Curl implements \Magento\Analytics\Model\Connector\Http\ClientInterface { /** * @var CurlFactory - * @since 2.2.0 */ private $curlFactory; /** * @var ResponseFactory - * @since 2.2.0 */ private $responseFactory; /** * @var ConverterInterface - * @since 2.2.0 */ private $converter; /** * @var LoggerInterface - * @since 2.2.0 */ private $logger; @@ -47,7 +42,6 @@ class Curl implements \Magento\Analytics\Model\Connector\Http\ClientInterface * @param ResponseFactory $responseFactory * @param ConverterInterface $converter * @param LoggerInterface $logger - * @since 2.2.0 */ public function __construct( CurlFactory $curlFactory, @@ -63,7 +57,6 @@ public function __construct( /** * {@inheritdoc} - * @since 2.2.0 */ public function request($method, $url, array $body = [], array $headers = [], $version = '1.1') { @@ -103,7 +96,6 @@ public function request($method, $url, array $body = [], array $headers = [], $v * @param array $headers * * @return array - * @since 2.2.0 */ private function applyContentTypeHeaderFromConverter(array $headers) { diff --git a/app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php b/app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php index aa2a8ca2cbf1a..a1e1f057684f6 100644 --- a/app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php +++ b/app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php @@ -9,7 +9,6 @@ * An interface for an HTTP client. * * Sends requests via a proper adapter. - * @since 2.2.0 */ interface ClientInterface { @@ -25,7 +24,6 @@ interface ClientInterface * @param string $version * * @return \Zend_Http_Response - * @since 2.2.0 */ public function request($method, $url, array $body = [], array $headers = [], $version = '1.1'); } diff --git a/app/code/Magento/Analytics/Model/Connector/Http/ConverterInterface.php b/app/code/Magento/Analytics/Model/Connector/Http/ConverterInterface.php index 826332b0169ac..a6ce85cadc62f 100644 --- a/app/code/Magento/Analytics/Model/Connector/Http/ConverterInterface.php +++ b/app/code/Magento/Analytics/Model/Connector/Http/ConverterInterface.php @@ -7,7 +7,6 @@ /** * Represents converter interface for http request and response body. - * @since 2.2.0 */ interface ConverterInterface { @@ -15,7 +14,6 @@ interface ConverterInterface * @param string $body * * @return array - * @since 2.2.0 */ public function fromBody($body); @@ -23,13 +21,11 @@ public function fromBody($body); * @param array $data * * @return string - * @since 2.2.0 */ public function toBody(array $data); /** * @return string - * @since 2.2.0 */ public function getContentTypeHeader(); } diff --git a/app/code/Magento/Analytics/Model/Connector/Http/JsonConverter.php b/app/code/Magento/Analytics/Model/Connector/Http/JsonConverter.php index 78d308305a5c8..4a0f27f245316 100644 --- a/app/code/Magento/Analytics/Model/Connector/Http/JsonConverter.php +++ b/app/code/Magento/Analytics/Model/Connector/Http/JsonConverter.php @@ -7,7 +7,6 @@ /** * Represents JSON converter for http request and response body. - * @since 2.2.0 */ class JsonConverter implements ConverterInterface { @@ -20,7 +19,6 @@ class JsonConverter implements ConverterInterface * @param string $body * * @return array - * @since 2.2.0 */ public function fromBody($body) { @@ -32,7 +30,6 @@ public function fromBody($body) * @param array $data * * @return string - * @since 2.2.0 */ public function toBody(array $data) { @@ -41,7 +38,6 @@ public function toBody(array $data) /** * @return string - * @since 2.2.0 */ public function getContentTypeHeader() { diff --git a/app/code/Magento/Analytics/Model/Connector/Http/ResponseFactory.php b/app/code/Magento/Analytics/Model/Connector/Http/ResponseFactory.php index fe13cdfdde253..77d23b88529a3 100644 --- a/app/code/Magento/Analytics/Model/Connector/Http/ResponseFactory.php +++ b/app/code/Magento/Analytics/Model/Connector/Http/ResponseFactory.php @@ -7,7 +7,6 @@ /** * A factory for an HTTP response. - * @since 2.2.0 */ class ResponseFactory { @@ -16,7 +15,6 @@ class ResponseFactory * * @param string $response * @return \Zend_Http_Response - * @since 2.2.0 */ public function create($response) { diff --git a/app/code/Magento/Analytics/Model/Connector/Http/ResponseHandlerInterface.php b/app/code/Magento/Analytics/Model/Connector/Http/ResponseHandlerInterface.php index 51faa8ecc8f31..4a6633f08da55 100644 --- a/app/code/Magento/Analytics/Model/Connector/Http/ResponseHandlerInterface.php +++ b/app/code/Magento/Analytics/Model/Connector/Http/ResponseHandlerInterface.php @@ -7,14 +7,12 @@ /** * Represents an interface for response handler which process response body. - * @since 2.2.0 */ interface ResponseHandlerInterface { /** * @param array $responseBody * @return bool|string - * @since 2.2.0 */ public function handleResponse(array $responseBody); } diff --git a/app/code/Magento/Analytics/Model/Connector/Http/ResponseResolver.php b/app/code/Magento/Analytics/Model/Connector/Http/ResponseResolver.php index 9041929ad1b33..ec198e4a3c40b 100644 --- a/app/code/Magento/Analytics/Model/Connector/Http/ResponseResolver.php +++ b/app/code/Magento/Analytics/Model/Connector/Http/ResponseResolver.php @@ -7,26 +7,22 @@ /** * Extract result from http response. Call response handler by status. - * @since 2.2.0 */ class ResponseResolver { /** * @var ConverterInterface - * @since 2.2.0 */ private $converter; /** * @var array - * @since 2.2.0 */ private $responseHandlers; /** * @param ConverterInterface $converter * @param ResponseHandlerInterface[] $responseHandlers - * @since 2.2.0 */ public function __construct(ConverterInterface $converter, array $responseHandlers = []) { @@ -38,7 +34,6 @@ public function __construct(ConverterInterface $converter, array $responseHandle * @param \Zend_Http_Response $response * * @return bool|string - * @since 2.2.0 */ public function getResult(\Zend_Http_Response $response) { diff --git a/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php b/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php index a88b87a447072..f1a8ea6460f9d 100644 --- a/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php +++ b/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php @@ -14,43 +14,36 @@ /** * Command notifies MBI about that data collection was finished. - * @since 2.2.0 */ class NotifyDataChangedCommand implements CommandInterface { /** * @var string - * @since 2.2.0 */ private $notifyDataChangedUrlPath = 'analytics/url/notify_data_changed'; /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var Http\ClientInterface - * @since 2.2.0 */ private $httpClient; /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $config; /** * @var ResponseResolver - * @since 2.2.0 */ private $responseResolver; /** * @var LoggerInterface - * @since 2.2.0 */ private $logger; @@ -61,7 +54,6 @@ class NotifyDataChangedCommand implements CommandInterface * @param ScopeConfigInterface $config * @param ResponseResolver $responseResolver * @param LoggerInterface $logger - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -81,7 +73,6 @@ public function __construct( * Notify MBI about that data collection was finished * * @return bool - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Model/Connector/OTPRequest.php b/app/code/Magento/Analytics/Model/Connector/OTPRequest.php index f0577084cbff3..dfa283e10d070 100644 --- a/app/code/Magento/Analytics/Model/Connector/OTPRequest.php +++ b/app/code/Magento/Analytics/Model/Connector/OTPRequest.php @@ -19,7 +19,6 @@ * * OTP (One-Time Password) is a password that is valid for short period of time * and may be used only for one login session. - * @since 2.2.0 */ class OTPRequest { @@ -27,31 +26,26 @@ class OTPRequest * Resource for handling MBI token value. * * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var Http\ClientInterface - * @since 2.2.0 */ private $httpClient; /** * @var LoggerInterface - * @since 2.2.0 */ private $logger; /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $config; /** * @var ResponseResolver - * @since 2.2.0 */ private $responseResolver; @@ -60,7 +54,6 @@ class OTPRequest * an URL that provides an OTP. * * @var string - * @since 2.2.0 */ private $otpUrlConfigPath = 'analytics/url/otp'; @@ -70,7 +63,6 @@ class OTPRequest * @param ScopeConfigInterface $config * @param ResponseResolver $responseResolver * @param LoggerInterface $logger - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -92,7 +84,6 @@ public function __construct( * Returns received OTP or FALSE in case of failure. * * @return string|false - * @since 2.2.0 */ public function call() { diff --git a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php index d385f466e2919..d9a672e81f43d 100644 --- a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php +++ b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php @@ -9,7 +9,6 @@ /** * Fetches OTP from body. - * @since 2.2.0 */ class OTP implements ResponseHandlerInterface { @@ -17,7 +16,6 @@ class OTP implements ResponseHandlerInterface * @param array $responseBody * * @return bool|string - * @since 2.2.0 */ public function handleResponse(array $responseBody) { diff --git a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/ReSignUp.php b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/ReSignUp.php index e15dbe48a7597..c79630d6414d8 100644 --- a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/ReSignUp.php +++ b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/ReSignUp.php @@ -12,25 +12,21 @@ /** * Removes stored token and triggers subscription process. - * @since 2.2.0 */ class ReSignUp implements ResponseHandlerInterface { /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var SubscriptionHandler - * @since 2.2.0 */ private $subscriptionHandler; /** * @var SubscriptionStatusProvider - * @since 2.2.0 */ private $subscriptionStatusProvider; @@ -38,7 +34,6 @@ class ReSignUp implements ResponseHandlerInterface * @param AnalyticsToken $analyticsToken * @param SubscriptionHandler $subscriptionHandler * @param SubscriptionStatusProvider $subscriptionStatusProvider - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -52,7 +47,6 @@ public function __construct( /** * @inheritdoc - * @since 2.2.0 */ public function handleResponse(array $responseBody) { diff --git a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php index 49ad1936a3975..b2261e418abc7 100644 --- a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php +++ b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php @@ -11,26 +11,22 @@ /** * Stores access token to MBI that received in body. - * @since 2.2.0 */ class SignUp implements ResponseHandlerInterface { /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var ConverterInterface - * @since 2.2.0 */ private $converter; /** * @param AnalyticsToken $analyticsToken * @param ConverterInterface $converter - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -42,7 +38,6 @@ public function __construct( /** * @inheritdoc - * @since 2.2.0 */ public function handleResponse(array $body) { diff --git a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php index 13a7eaa9b1fd8..73fc575ae2821 100644 --- a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php +++ b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php @@ -9,7 +9,6 @@ /** * Return positive answer that request was finished successfully. - * @since 2.2.0 */ class Update implements ResponseHandlerInterface { @@ -17,7 +16,6 @@ class Update implements ResponseHandlerInterface * @param array $responseBody * * @return bool|string - * @since 2.2.0 */ public function handleResponse(array $responseBody) { diff --git a/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php b/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php index a52e79182ce0c..a1f23637e04b1 100644 --- a/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php +++ b/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php @@ -17,49 +17,41 @@ * Class SignUpCommand * * SignUp merchant for Free Tier project - * @since 2.2.0 */ class SignUpCommand implements CommandInterface { /** * @var string - * @since 2.2.0 */ private $signUpUrlPath = 'analytics/url/signup'; /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var IntegrationManager - * @since 2.2.0 */ private $integrationManager; /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $config; /** * @var Http\ClientInterface - * @since 2.2.0 */ private $httpClient; /** * @var LoggerInterface - * @since 2.2.0 */ private $logger; /** * @var ResponseResolver - * @since 2.2.0 */ private $responseResolver; @@ -72,7 +64,6 @@ class SignUpCommand implements CommandInterface * @param Http\ClientInterface $httpClient * @param LoggerInterface $logger * @param ResponseResolver $responseResolver - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -101,7 +92,6 @@ public function __construct( * This method returns true in case of success * * @return bool - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php b/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php index ff8ad2ec85a43..8f05f1107e87e 100644 --- a/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php +++ b/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php @@ -17,49 +17,41 @@ /** * Class UpdateCommand * Command executes in case change store url - * @since 2.2.0 */ class UpdateCommand implements CommandInterface { /** * @var string - * @since 2.2.0 */ private $updateUrlPath = 'analytics/url/update'; /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var Http\ClientInterface - * @since 2.2.0 */ private $httpClient; /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $config; /** * @var LoggerInterface - * @since 2.2.0 */ private $logger; /** * @var FlagManager - * @since 2.2.0 */ private $flagManager; /** * @var ResponseResolver - * @since 2.2.0 */ private $responseResolver; @@ -70,7 +62,6 @@ class UpdateCommand implements CommandInterface * @param LoggerInterface $logger * @param FlagManager $flagManager * @param ResponseResolver $responseResolver - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -92,7 +83,6 @@ public function __construct( * Executes update request to MBI api in case store url was changed * * @return bool - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Model/Cryptographer.php b/app/code/Magento/Analytics/Model/Cryptographer.php index 848d2911e9a5e..6905eee372ae2 100644 --- a/app/code/Magento/Analytics/Model/Cryptographer.php +++ b/app/code/Magento/Analytics/Model/Cryptographer.php @@ -9,7 +9,6 @@ /** * Class for encrypting data. - * @since 2.2.0 */ class Cryptographer { @@ -17,7 +16,6 @@ class Cryptographer * Resource for handling MBI token value. * * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; @@ -25,20 +23,17 @@ class Cryptographer * Cipher method for encryption. * * @var string - * @since 2.2.0 */ private $cipherMethod = 'AES-256-CBC'; /** * @var EncodedContextFactory - * @since 2.2.0 */ private $encodedContextFactory; /** * @param AnalyticsToken $analyticsToken * @param EncodedContextFactory $encodedContextFactory - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -54,7 +49,6 @@ public function __construct( * @param string $source * @return EncodedContext * @throws LocalizedException - * @since 2.2.0 */ public function encode($source) { @@ -91,7 +85,6 @@ public function encode($source) * * @return string * @throws LocalizedException - * @since 2.2.0 */ private function getKey() { @@ -106,7 +99,6 @@ private function getKey() * Return established cipher method. * * @return string - * @since 2.2.0 */ private function getCipherMethod() { @@ -117,7 +109,6 @@ private function getCipherMethod() * Return each time generated random initialization vector which depends on the cipher method. * * @return string - * @since 2.2.0 */ private function getInitializationVector() { @@ -130,7 +121,6 @@ private function getInitializationVector() * * @param string $cipherMethod * @return bool - * @since 2.2.0 */ private function validateCipherMethod($cipherMethod) { diff --git a/app/code/Magento/Analytics/Model/EncodedContext.php b/app/code/Magento/Analytics/Model/EncodedContext.php index bffbf29315c11..5fb2d0c15aef7 100644 --- a/app/code/Magento/Analytics/Model/EncodedContext.php +++ b/app/code/Magento/Analytics/Model/EncodedContext.php @@ -7,7 +7,6 @@ /** * Contain information about encrypted data. - * @since 2.2.0 */ class EncodedContext { @@ -15,7 +14,6 @@ class EncodedContext * Encrypted string. * * @var string - * @since 2.2.0 */ private $content; @@ -23,14 +21,12 @@ class EncodedContext * Initialization vector that was used for encryption. * * @var string - * @since 2.2.0 */ private $initializationVector; /** * @param string $content * @param string $initializationVector - * @since 2.2.0 */ public function __construct($content, $initializationVector = '') { @@ -40,7 +36,6 @@ public function __construct($content, $initializationVector = '') /** * @return string - * @since 2.2.0 */ public function getContent() { @@ -49,7 +44,6 @@ public function getContent() /** * @return string - * @since 2.2.0 */ public function getInitializationVector() { diff --git a/app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php b/app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php index 74cfd28365678..5d127037afea9 100644 --- a/app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php +++ b/app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php @@ -10,7 +10,6 @@ /** * Analytics is in update subscription mode. - * @since 2.2.0 */ class SubscriptionUpdateException extends LocalizedException { diff --git a/app/code/Magento/Analytics/Model/ExportDataHandler.php b/app/code/Magento/Analytics/Model/ExportDataHandler.php index 37611df7e2ec8..b9d3b6340184b 100644 --- a/app/code/Magento/Analytics/Model/ExportDataHandler.php +++ b/app/code/Magento/Analytics/Model/ExportDataHandler.php @@ -14,7 +14,6 @@ /** * Class for the handling of a new data collection for MBI. - * @since 2.2.0 */ class ExportDataHandler implements ExportDataHandlerInterface { @@ -22,7 +21,6 @@ class ExportDataHandler implements ExportDataHandlerInterface * Subdirectory path for all temporary files. * * @var string - * @since 2.2.0 */ private $subdirectoryPath = 'analytics/'; @@ -30,19 +28,16 @@ class ExportDataHandler implements ExportDataHandlerInterface * Filename of archive with collected data. * * @var string - * @since 2.2.0 */ private $archiveName = 'data.tgz'; /** * @var Filesystem - * @since 2.2.0 */ private $filesystem; /** * @var Archive - * @since 2.2.0 */ private $archive; @@ -50,7 +45,6 @@ class ExportDataHandler implements ExportDataHandlerInterface * Resource for write data of reports into separate files. * * @var ReportWriterInterface - * @since 2.2.0 */ private $reportWriter; @@ -58,7 +52,6 @@ class ExportDataHandler implements ExportDataHandlerInterface * Resource for encrypting data. * * @var Cryptographer - * @since 2.2.0 */ private $cryptographer; @@ -66,7 +59,6 @@ class ExportDataHandler implements ExportDataHandlerInterface * Resource for registration a new file. * * @var FileRecorder - * @since 2.2.0 */ private $fileRecorder; @@ -76,7 +68,6 @@ class ExportDataHandler implements ExportDataHandlerInterface * @param ReportWriterInterface $reportWriter * @param Cryptographer $cryptographer * @param FileRecorder $fileRecorder - * @since 2.2.0 */ public function __construct( Filesystem $filesystem, @@ -94,7 +85,6 @@ public function __construct( /** * @inheritdoc - * @since 2.2.0 */ public function prepareExportData() { @@ -127,7 +117,6 @@ public function prepareExportData() * Return relative path to a directory for temporary files with reports data. * * @return string - * @since 2.2.0 */ private function getTmpFilesDirRelativePath() { @@ -138,7 +127,6 @@ private function getTmpFilesDirRelativePath() * Return relative path to a directory for an archive. * * @return string - * @since 2.2.0 */ private function getArchiveRelativePath() { @@ -151,7 +139,6 @@ private function getArchiveRelativePath() * @param WriteInterface $directory * @param string $path * @return string - * @since 2.2.0 */ private function prepareDirectory(WriteInterface $directory, $path) { @@ -166,7 +153,6 @@ private function prepareDirectory(WriteInterface $directory, $path) * @param WriteInterface $directory * @param string $path * @return string - * @since 2.2.0 */ private function prepareFileDirectory(WriteInterface $directory, $path) { @@ -184,7 +170,6 @@ private function prepareFileDirectory(WriteInterface $directory, $path) * @param string $source * @param string $destination * @return bool - * @since 2.2.0 */ private function pack($source, $destination) { @@ -206,7 +191,6 @@ private function pack($source, $destination) * @param string $path * @return string * @throws LocalizedException If source is not exist. - * @since 2.2.0 */ private function validateSource(WriteInterface $directory, $path) { diff --git a/app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php b/app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php index c8af595c2aadf..65efb33659c89 100644 --- a/app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php +++ b/app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php @@ -7,7 +7,6 @@ /** * The interface represents the type of classes that handling of a new data collection for MBI. - * @since 2.2.0 */ interface ExportDataHandlerInterface { @@ -15,7 +14,6 @@ interface ExportDataHandlerInterface * Execute collecting new data for MBI. * * @return bool - * @since 2.2.0 */ public function prepareExportData(); } diff --git a/app/code/Magento/Analytics/Model/ExportDataHandlerNotification.php b/app/code/Magento/Analytics/Model/ExportDataHandlerNotification.php index 1f995fb92d27f..34941ac9ae2f2 100644 --- a/app/code/Magento/Analytics/Model/ExportDataHandlerNotification.php +++ b/app/code/Magento/Analytics/Model/ExportDataHandlerNotification.php @@ -7,19 +7,16 @@ /** * Class which add notification behaviour to classes that handling of a new data collection for MBI. - * @since 2.2.0 */ class ExportDataHandlerNotification implements ExportDataHandlerInterface { /** * @var ExportDataHandler - * @since 2.2.0 */ private $exportDataHandler; /** * @var Connector - * @since 2.2.0 */ private $analyticsConnector; @@ -28,7 +25,6 @@ class ExportDataHandlerNotification implements ExportDataHandlerInterface * * @param ExportDataHandlerInterface $exportDataHandler * @param Connector $connector - * @since 2.2.0 */ public function __construct(ExportDataHandler $exportDataHandler, Connector $connector) { @@ -41,7 +37,6 @@ public function __construct(ExportDataHandler $exportDataHandler, Connector $con * Execute notification command. * * @return bool - * @since 2.2.0 */ public function prepareExportData() { diff --git a/app/code/Magento/Analytics/Model/FileInfo.php b/app/code/Magento/Analytics/Model/FileInfo.php index edfac858d6f68..19bdaf21b2a20 100644 --- a/app/code/Magento/Analytics/Model/FileInfo.php +++ b/app/code/Magento/Analytics/Model/FileInfo.php @@ -7,7 +7,6 @@ /** * Contain information about encrypted file. - * @since 2.2.0 */ class FileInfo { @@ -15,7 +14,6 @@ class FileInfo * Initialization vector that was used for encryption. * * @var string - * @since 2.2.0 */ private $initializationVector; @@ -23,14 +21,12 @@ class FileInfo * Relative path to an encrypted file. * * @var string - * @since 2.2.0 */ private $path; /** * @param string $path * @param string $initializationVector - * @since 2.2.0 */ public function __construct($path = '', $initializationVector = '') { @@ -40,7 +36,6 @@ public function __construct($path = '', $initializationVector = '') /** * @return string - * @since 2.2.0 */ public function getPath() { @@ -49,7 +44,6 @@ public function getPath() /** * @return string - * @since 2.2.0 */ public function getInitializationVector() { diff --git a/app/code/Magento/Analytics/Model/FileInfoManager.php b/app/code/Magento/Analytics/Model/FileInfoManager.php index 204995e133d20..e37700e665420 100644 --- a/app/code/Magento/Analytics/Model/FileInfoManager.php +++ b/app/code/Magento/Analytics/Model/FileInfoManager.php @@ -10,19 +10,16 @@ /** * Manage saving and loading FileInfo object. - * @since 2.2.0 */ class FileInfoManager { /** * @var FlagManager - * @since 2.2.0 */ private $flagManager; /** * @var FileInfoFactory - * @since 2.2.0 */ private $fileInfoFactory; @@ -30,7 +27,6 @@ class FileInfoManager * Flag code for a stored FileInfo object. * * @var string - * @since 2.2.0 */ private $flagCode = 'analytics_file_info'; @@ -38,7 +34,6 @@ class FileInfoManager * Parameters which have to be saved into encoded form. * * @var array - * @since 2.2.0 */ private $encodedParameters = [ 'initializationVector' @@ -47,7 +42,6 @@ class FileInfoManager /** * @param FlagManager $flagManager * @param FileInfoFactory $fileInfoFactory - * @since 2.2.0 */ public function __construct( FlagManager $flagManager, @@ -63,7 +57,6 @@ public function __construct( * @param FileInfo $fileInfo * @return bool * @throws LocalizedException - * @since 2.2.0 */ public function save(FileInfo $fileInfo) { @@ -91,7 +84,6 @@ public function save(FileInfo $fileInfo) * Load FileInfo object. * * @return FileInfo - * @since 2.2.0 */ public function load() { @@ -112,7 +104,6 @@ public function load() * * @param string $value * @return string - * @since 2.2.0 */ private function encodeValue($value) { @@ -124,7 +115,6 @@ private function encodeValue($value) * * @param string $value * @return string - * @since 2.2.0 */ private function decodeValue($value) { diff --git a/app/code/Magento/Analytics/Model/FileRecorder.php b/app/code/Magento/Analytics/Model/FileRecorder.php index 94e0c59d9321b..70438a98d56f1 100644 --- a/app/code/Magento/Analytics/Model/FileRecorder.php +++ b/app/code/Magento/Analytics/Model/FileRecorder.php @@ -11,7 +11,6 @@ /** * Class for the handling of registration a new file for MBI. - * @since 2.2.0 */ class FileRecorder { @@ -19,13 +18,11 @@ class FileRecorder * Resource for managing FileInfo object. * * @var FileInfoManager - * @since 2.2.0 */ private $fileInfoManager; /** * @var FileInfoFactory - * @since 2.2.0 */ private $fileInfoFactory; @@ -33,7 +30,6 @@ class FileRecorder * Subdirectory path for an encoded file. * * @var string - * @since 2.2.0 */ private $fileSubdirectoryPath = 'analytics/'; @@ -41,13 +37,11 @@ class FileRecorder * File name of an encoded file. * * @var string - * @since 2.2.0 */ private $encodedFileName = 'data.tgz'; /** * @var Filesystem - * @since 2.2.0 */ private $filesystem; @@ -55,7 +49,6 @@ class FileRecorder * @param FileInfoManager $fileInfoManager * @param FileInfoFactory $fileInfoFactory * @param Filesystem $filesystem - * @since 2.2.0 */ public function __construct( FileInfoManager $fileInfoManager, @@ -72,7 +65,6 @@ public function __construct( * * @param EncodedContext $encodedContext * @return bool - * @since 2.2.0 */ public function recordNewFile(EncodedContext $encodedContext) { @@ -92,7 +84,6 @@ public function recordNewFile(EncodedContext $encodedContext) * Return relative path to encoded file. * * @return string - * @since 2.2.0 */ private function getFileRelativePath() { @@ -106,7 +97,6 @@ private function getFileRelativePath() * @param EncodedContext $encodedContext * @param string $fileRelativePath * @return bool - * @since 2.2.0 */ private function registerFile(EncodedContext $encodedContext, $fileRelativePath) { @@ -127,7 +117,6 @@ private function registerFile(EncodedContext $encodedContext, $fileRelativePath) * @param FileInfo $fileInfo * @param WriteInterface $directory * @return bool - * @since 2.2.0 */ private function removeOldFile(FileInfo $fileInfo, WriteInterface $directory) { diff --git a/app/code/Magento/Analytics/Model/IntegrationManager.php b/app/code/Magento/Analytics/Model/IntegrationManager.php index b2694ac8241c1..61a40a955e026 100644 --- a/app/code/Magento/Analytics/Model/IntegrationManager.php +++ b/app/code/Magento/Analytics/Model/IntegrationManager.php @@ -18,25 +18,21 @@ * Manages the integration user at magento side. * User name stored in config. * User roles - * @since 2.2.0 */ class IntegrationManager { /** * @var SystemConfig - * @since 2.2.0 */ private $config; /** * @var IntegrationServiceInterface - * @since 2.2.0 */ private $integrationService; /** * @var OauthServiceInterface - * @since 2.2.0 */ private $oauthService; @@ -46,7 +42,6 @@ class IntegrationManager * @param SystemConfig $config * @param IntegrationServiceInterface $integrationService * @param OauthServiceInterface $oauthService - * @since 2.2.0 */ public function __construct( SystemConfig $config, @@ -63,7 +58,6 @@ public function __construct( * * @return bool * @throws NoSuchEntityException - * @since 2.2.0 */ public function activateIntegration() { @@ -83,7 +77,6 @@ public function activateIntegration() * This method execute Generate Token command and enable integration * * @return bool|\Magento\Integration\Model\Oauth\Token - * @since 2.2.0 */ public function generateToken() { @@ -99,7 +92,6 @@ public function generateToken() * Returns consumer Id for MA integration user * * @return \Magento\Integration\Model\Integration - * @since 2.2.0 */ private function generateIntegration() { @@ -117,7 +109,6 @@ private function generateIntegration() * * @param int $status * @return array - * @since 2.2.0 */ private function getIntegrationData($status = Integration::STATUS_INACTIVE) { diff --git a/app/code/Magento/Analytics/Model/Link.php b/app/code/Magento/Analytics/Model/Link.php index 34479e9ae4f61..4a40796df4fd0 100644 --- a/app/code/Magento/Analytics/Model/Link.php +++ b/app/code/Magento/Analytics/Model/Link.php @@ -11,19 +11,16 @@ * Class Link * * Represents link with collected data and initialized vector for decryption. - * @since 2.2.0 */ class Link implements LinkInterface { /** * @var string - * @since 2.2.0 */ private $url; /** * @var string - * @since 2.2.0 */ private $initializationVector; @@ -32,7 +29,6 @@ class Link implements LinkInterface * * @param string $url * @param string $initializationVector - * @since 2.2.0 */ public function __construct($url, $initializationVector) { @@ -42,7 +38,6 @@ public function __construct($url, $initializationVector) /** * @return string - * @since 2.2.0 */ public function getUrl() { @@ -51,7 +46,6 @@ public function getUrl() /** * @return string - * @since 2.2.0 */ public function getInitializationVector() { diff --git a/app/code/Magento/Analytics/Model/LinkProvider.php b/app/code/Magento/Analytics/Model/LinkProvider.php index 6d09e20fef1a4..2474653f4916c 100644 --- a/app/code/Magento/Analytics/Model/LinkProvider.php +++ b/app/code/Magento/Analytics/Model/LinkProvider.php @@ -13,25 +13,21 @@ /** * Provides link to file with collected report data. - * @since 2.2.0 */ class LinkProvider implements LinkProviderInterface { /** * @var LinkInterfaceFactory - * @since 2.2.0 */ private $linkFactory; /** * @var FileInfoManager - * @since 2.2.0 */ private $fileInfoManager; /** * @var StoreManagerInterface - * @since 2.2.0 */ private $storeManager; @@ -39,7 +35,6 @@ class LinkProvider implements LinkProviderInterface * @param LinkInterfaceFactory $linkInterfaceFactory * @param FileInfoManager $fileInfoManager * @param StoreManagerInterface $storeManager - * @since 2.2.0 */ public function __construct( LinkInterfaceFactory $linkFactory, @@ -56,7 +51,6 @@ public function __construct( * * @param FileInfo $fileInfo * @return string - * @since 2.2.0 */ private function getBaseUrl(FileInfo $fileInfo) { @@ -68,7 +62,6 @@ private function getBaseUrl(FileInfo $fileInfo) * * @param FileInfo $fileInfo * @return bool - * @since 2.2.0 */ private function isFileReady(FileInfo $fileInfo) { @@ -77,7 +70,6 @@ private function isFileReady(FileInfo $fileInfo) /** * @inheritdoc - * @since 2.2.0 */ public function get() { diff --git a/app/code/Magento/Analytics/Model/NotificationTime.php b/app/code/Magento/Analytics/Model/NotificationTime.php index b831c4e20dc5f..c3ebf52da4b99 100644 --- a/app/code/Magento/Analytics/Model/NotificationTime.php +++ b/app/code/Magento/Analytics/Model/NotificationTime.php @@ -14,7 +14,6 @@ * * Manage access to notification time flag * - * @since 2.2.2 */ class NotificationTime { @@ -22,19 +21,16 @@ class NotificationTime /** * @var FlagManager - * @since 2.2.2 */ private $flagManager; /** * @var UserContextInterface - * @since 2.2.2 */ private $userContext; /** * @var DateTimeFactory - * @since 2.2.2 */ private $dateTimeFactory; @@ -44,7 +40,6 @@ class NotificationTime * @param FlagManager $flagManager * @param UserContextInterface $userContext * @param DateTimeFactory $dateTimeFactory - * @since 2.2.2 */ public function __construct( FlagManager $flagManager, @@ -60,7 +55,6 @@ public function __construct( * Stores last notification time * * @return bool - * @since 2.2.2 */ public function storeLastTimeNotificationForCurrentUser() { @@ -73,7 +67,6 @@ public function storeLastTimeNotificationForCurrentUser() * Returns last time when merchant was notified about Analytic services * * @return int - * @since 2.2.2 */ public function getLastTimeNotificationForCurrentUser() { @@ -84,7 +77,6 @@ public function getLastTimeNotificationForCurrentUser() * Remove last notification time flag. * * @return bool - * @since 2.2.2 */ public function unsetLastTimeNotificationValueForCurrentUser() { diff --git a/app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php b/app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php index e2bdf354b040c..174272614fb19 100644 --- a/app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php +++ b/app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php @@ -12,19 +12,16 @@ /** * Plugin on Base URL config value AfterSave method. - * @since 2.2.0 */ class BaseUrlConfigPlugin { /** * @var SubscriptionUpdateHandler - * @since 2.2.0 */ private $subscriptionUpdateHandler; /** * @param SubscriptionUpdateHandler $subscriptionUpdateHandler - * @since 2.2.0 */ public function __construct( SubscriptionUpdateHandler $subscriptionUpdateHandler @@ -39,7 +36,6 @@ public function __construct( * @param Value $result * @return Value * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function afterAfterSave( Value $subject, @@ -55,7 +51,6 @@ public function afterAfterSave( /** * @param Value $result * @return bool - * @since 2.2.0 */ private function isPluginApplicable(Value $result) { diff --git a/app/code/Magento/Analytics/Model/ProviderFactory.php b/app/code/Magento/Analytics/Model/ProviderFactory.php index 35af7d5ddaa1c..3a23430fca077 100644 --- a/app/code/Magento/Analytics/Model/ProviderFactory.php +++ b/app/code/Magento/Analytics/Model/ProviderFactory.php @@ -11,19 +11,16 @@ * Class ProviderFactory * * Factory for report providers - * @since 2.2.0 */ class ProviderFactory { /** * @var ObjectManagerInterface - * @since 2.2.0 */ private $objectManager; /** * @param ObjectManagerInterface $objectManager - * @since 2.2.0 */ public function __construct( ObjectManagerInterface $objectManager @@ -34,7 +31,6 @@ public function __construct( /** * @param string $providerName * @return object - * @since 2.2.0 */ public function create($providerName) { diff --git a/app/code/Magento/Analytics/Model/ReportUrlProvider.php b/app/code/Magento/Analytics/Model/ReportUrlProvider.php index dfa27358e252b..e7fdf6f9e8132 100644 --- a/app/code/Magento/Analytics/Model/ReportUrlProvider.php +++ b/app/code/Magento/Analytics/Model/ReportUrlProvider.php @@ -13,7 +13,6 @@ /** * Provide URL on resource with reports. - * @since 2.2.0 */ class ReportUrlProvider { @@ -21,7 +20,6 @@ class ReportUrlProvider * Resource for handling MBI token value. * * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; @@ -29,19 +27,16 @@ class ReportUrlProvider * Resource which provide OTP. * * @var OTPRequest - * @since 2.2.0 */ private $otpRequest; /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $config; /** * @var FlagManager - * @since 2.2.0 */ private $flagManager; @@ -49,7 +44,6 @@ class ReportUrlProvider * Path to config value with URL which provide reports. * * @var string - * @since 2.2.0 */ private $urlReportConfigPath = 'analytics/url/report'; @@ -58,7 +52,6 @@ class ReportUrlProvider * @param OTPRequest $otpRequest * @param ScopeConfigInterface $config * @param FlagManager $flagManager - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -77,7 +70,6 @@ public function __construct( * * @return string * @throws SubscriptionUpdateException - * @since 2.2.0 */ public function getUrl() { diff --git a/app/code/Magento/Analytics/Model/ReportWriter.php b/app/code/Magento/Analytics/Model/ReportWriter.php index ae3522c6f4351..7128658947908 100644 --- a/app/code/Magento/Analytics/Model/ReportWriter.php +++ b/app/code/Magento/Analytics/Model/ReportWriter.php @@ -11,7 +11,6 @@ /** * Writes reports in files in csv format * @inheritdoc - * @since 2.2.0 */ class ReportWriter implements ReportWriterInterface { @@ -19,25 +18,21 @@ class ReportWriter implements ReportWriterInterface * File name for error reporting file in archive * * @var string - * @since 2.2.0 */ private $errorsFileName = 'errors.csv'; /** * @var Config - * @since 2.2.0 */ private $config; /** * @var ProviderFactory - * @since 2.2.0 */ private $providerFactory; /** * @var ReportValidator - * @since 2.2.0 */ private $reportValidator; @@ -47,7 +42,6 @@ class ReportWriter implements ReportWriterInterface * @param ConfigInterface $config * @param ReportValidator $reportValidator * @param ProviderFactory $providerFactory - * @since 2.2.0 */ public function __construct( ConfigInterface $config, @@ -61,7 +55,6 @@ public function __construct( /** * {@inheritdoc} - * @since 2.2.0 */ public function write(WriteInterface $directory, $path) { diff --git a/app/code/Magento/Analytics/Model/ReportWriterInterface.php b/app/code/Magento/Analytics/Model/ReportWriterInterface.php index bb7f8dfbe26a6..a611095a47ae4 100644 --- a/app/code/Magento/Analytics/Model/ReportWriterInterface.php +++ b/app/code/Magento/Analytics/Model/ReportWriterInterface.php @@ -14,7 +14,6 @@ * Executes export of collected data * Iterates registered providers @see etc/analytics.xml * Collects data (to TMP folder) - * @since 2.2.0 */ interface ReportWriterInterface { @@ -24,7 +23,6 @@ interface ReportWriterInterface * @param WriteInterface $directory * @param string $path * @return void - * @since 2.2.0 */ public function write(WriteInterface $directory, $path); } diff --git a/app/code/Magento/Analytics/Model/ReportXml/ModuleIterator.php b/app/code/Magento/Analytics/Model/ReportXml/ModuleIterator.php index eabeccd260966..a0800387d28f5 100644 --- a/app/code/Magento/Analytics/Model/ReportXml/ModuleIterator.php +++ b/app/code/Magento/Analytics/Model/ReportXml/ModuleIterator.php @@ -9,13 +9,11 @@ /** * Class ModuleIterator - * @since 2.2.0 */ class ModuleIterator extends \IteratorIterator { /** * @var ModuleManager - * @since 2.2.0 */ private $moduleManager; @@ -24,7 +22,6 @@ class ModuleIterator extends \IteratorIterator * * @param ModuleManager $moduleManager * @param \Traversable $iterator - * @since 2.2.0 */ public function __construct( ModuleManager $moduleManager, @@ -38,7 +35,6 @@ public function __construct( * Returns module with module status * * @return array - * @since 2.2.0 */ public function current() { diff --git a/app/code/Magento/Analytics/Model/StoreConfigurationProvider.php b/app/code/Magento/Analytics/Model/StoreConfigurationProvider.php index e070e2c669ccf..0d226a9de7dc2 100644 --- a/app/code/Magento/Analytics/Model/StoreConfigurationProvider.php +++ b/app/code/Magento/Analytics/Model/StoreConfigurationProvider.php @@ -15,25 +15,21 @@ /** * Class StoreConfigurationProvider * Provides config data report - * @since 2.2.0 */ class StoreConfigurationProvider { /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $scopeConfig; /** * @var string[] - * @since 2.2.0 */ private $configPaths; /** * @var StoreManagerInterface - * @since 2.2.0 */ private $storeManager; @@ -41,7 +37,6 @@ class StoreConfigurationProvider * @param ScopeConfigInterface $scopeConfig * @param StoreManagerInterface $storeManager * @param string[] $configPaths - * @since 2.2.0 */ public function __construct( ScopeConfigInterface $scopeConfig, @@ -57,7 +52,6 @@ public function __construct( * Generates report using config paths from di.xml * For each website and store * @return \IteratorIterator - * @since 2.2.0 */ public function getReport() { @@ -87,7 +81,6 @@ public function getReport() * @param string $scope * @param int $scopeId * @return array - * @since 2.2.0 */ private function generateReportForScope($scope, $scopeId) { diff --git a/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php b/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php index 478e0ae4ccd63..1dd831a672faa 100644 --- a/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php +++ b/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php @@ -12,7 +12,6 @@ /** * Provider of subscription status. - * @since 2.2.0 */ class SubscriptionStatusProvider { @@ -38,19 +37,16 @@ class SubscriptionStatusProvider /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $scopeConfig; /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var FlagManager - * @since 2.2.0 */ private $flagManager; @@ -58,7 +54,6 @@ class SubscriptionStatusProvider * @param ScopeConfigInterface $scopeConfig * @param AnalyticsToken $analyticsToken * @param FlagManager $flagManager - * @since 2.2.0 */ public function __construct( ScopeConfigInterface $scopeConfig, @@ -80,7 +75,6 @@ public function __construct( * Failed - if subscription is enabled and token was not received after attempts ended. * * @return string - * @since 2.2.0 */ public function getStatus() { @@ -96,7 +90,6 @@ public function getStatus() * Retrieve status for subscription that enabled in config. * * @return string - * @since 2.2.0 */ public function getStatusForEnabledSubscription() { @@ -119,7 +112,6 @@ public function getStatusForEnabledSubscription() * Retrieve status for subscription that disabled in config. * * @return string - * @since 2.2.0 */ public function getStatusForDisabledSubscription() { diff --git a/app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php b/app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php index 688caedf8e864..9aaa2ebb3b56f 100644 --- a/app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php +++ b/app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php @@ -11,26 +11,22 @@ /** * Represents an analytics notification about failed subscription. - * @since 2.2.0 */ class NotificationAboutFailedSubscription implements MessageInterface { /** * @var SubscriptionStatusProvider - * @since 2.2.0 */ private $subscriptionStatusProvider; /** * @var UrlInterface - * @since 2.2.0 */ private $urlBuilder; /** * @param SubscriptionStatusProvider $subscriptionStatusProvider * @param UrlInterface $urlBuilder - * @since 2.2.0 */ public function __construct(SubscriptionStatusProvider $subscriptionStatusProvider, UrlInterface $urlBuilder) { @@ -42,7 +38,6 @@ public function __construct(SubscriptionStatusProvider $subscriptionStatusProvid * @inheritdoc * * @codeCoverageIgnore - * @since 2.2.0 */ public function getIdentity() { @@ -51,7 +46,6 @@ public function getIdentity() /** * {@inheritdoc} - * @since 2.2.0 */ public function isDisplayed() { @@ -60,7 +54,6 @@ public function isDisplayed() /** * {@inheritdoc} - * @since 2.2.0 */ public function getText() { @@ -79,7 +72,6 @@ public function getText() * @inheritdoc * * @codeCoverageIgnore - * @since 2.2.0 */ public function getSeverity() { diff --git a/app/code/Magento/Analytics/ReportXml/Config.php b/app/code/Magento/Analytics/ReportXml/Config.php index 4176486fd0993..f50dcf941bf50 100644 --- a/app/code/Magento/Analytics/ReportXml/Config.php +++ b/app/code/Magento/Analytics/ReportXml/Config.php @@ -11,13 +11,11 @@ * Class Config * * Config of ReportXml - * @since 2.2.0 */ class Config implements ConfigInterface { /** * @var DataInterface - * @since 2.2.0 */ private $data; @@ -25,7 +23,6 @@ class Config implements ConfigInterface * Config constructor. * * @param DataInterface $data - * @since 2.2.0 */ public function __construct( DataInterface $data @@ -38,7 +35,6 @@ public function __construct( * * @param string $queryName * @return array - * @since 2.2.0 */ public function get($queryName) { diff --git a/app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php b/app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php index a479b70c91945..9e0b20a6ad414 100644 --- a/app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php +++ b/app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php @@ -11,7 +11,6 @@ * A converter of reports configuration. * * Converts configuration data stored in XML format into corresponding PHP array. - * @since 2.2.0 */ class Xml implements ConverterInterface { @@ -20,7 +19,6 @@ class Xml implements ConverterInterface * * @param \DOMNode $source * @return array|string - * @since 2.2.0 */ private function convertNode(\DOMNode $source) { @@ -55,7 +53,6 @@ private function convertNode(\DOMNode $source) * * @param \DOMDocument $source * @return array - * @since 2.2.0 */ public function convert($source) { diff --git a/app/code/Magento/Analytics/ReportXml/Config/Mapper.php b/app/code/Magento/Analytics/ReportXml/Config/Mapper.php index 8da73e257b825..4dda8f3c733a6 100644 --- a/app/code/Magento/Analytics/ReportXml/Config/Mapper.php +++ b/app/code/Magento/Analytics/ReportXml/Config/Mapper.php @@ -11,7 +11,6 @@ * Transforms configuration data to improve its usability. * * @see usage examples in \Magento\Analytics\ReportXml\Config\Reader - * @since 2.2.0 */ class Mapper { @@ -20,7 +19,6 @@ class Mapper * * @param array $configData * @return array - * @since 2.2.0 */ public function execute($configData) { diff --git a/app/code/Magento/Analytics/ReportXml/Config/Reader.php b/app/code/Magento/Analytics/ReportXml/Config/Reader.php index 8636ede7c6f08..3e0bc3cb5c796 100644 --- a/app/code/Magento/Analytics/ReportXml/Config/Reader.php +++ b/app/code/Magento/Analytics/ReportXml/Config/Reader.php @@ -11,7 +11,6 @@ * A composite reader of reports configuration. * * Reads configuration data using declared readers. - * @since 2.2.0 */ class Reader implements ReaderInterface { @@ -21,20 +20,17 @@ class Reader implements ReaderInterface * The list may be configured in each module via '/etc/di.xml'. * * @var ReaderInterface[] - * @since 2.2.0 */ private $readers; /** * @var Mapper - * @since 2.2.0 */ private $mapper; /** * @param Mapper $mapper * @param array $readers - * @since 2.2.0 */ public function __construct( Mapper $mapper, @@ -49,7 +45,6 @@ public function __construct( * * @param string|null $scope * @return array - * @since 2.2.0 */ public function read($scope = null) { diff --git a/app/code/Magento/Analytics/ReportXml/ConfigInterface.php b/app/code/Magento/Analytics/ReportXml/ConfigInterface.php index b9271700f6758..ec03ddf429c06 100644 --- a/app/code/Magento/Analytics/ReportXml/ConfigInterface.php +++ b/app/code/Magento/Analytics/ReportXml/ConfigInterface.php @@ -10,7 +10,6 @@ * Interface ConfigInterface * * Interface for ReportXml Config - * @since 2.2.0 */ interface ConfigInterface { @@ -19,7 +18,6 @@ interface ConfigInterface * * @param string $queryName * @return array - * @since 2.2.0 */ public function get($queryName); } diff --git a/app/code/Magento/Analytics/ReportXml/ConnectionFactory.php b/app/code/Magento/Analytics/ReportXml/ConnectionFactory.php index 214d4a7d4cecd..e591ed2659651 100644 --- a/app/code/Magento/Analytics/ReportXml/ConnectionFactory.php +++ b/app/code/Magento/Analytics/ReportXml/ConnectionFactory.php @@ -15,19 +15,16 @@ * * Creates connection instance for export according to existing one * This connection does not use buffered statement, also this connection is not persistent - * @since 2.2.0 */ class ConnectionFactory { /** * @var ResourceConnection - * @since 2.2.0 */ private $resourceConnection; /** * @var ObjectManagerInterface - * @since 2.2.0 */ private $objectManager; @@ -36,7 +33,6 @@ class ConnectionFactory * * @param ResourceConnection $resourceConnection * @param ObjectManagerInterface $objectManager - * @since 2.2.0 */ public function __construct( ResourceConnection $resourceConnection, @@ -51,7 +47,6 @@ public function __construct( * * @param string $connectionName * @return AdapterInterface - * @since 2.2.0 */ public function getConnection($connectionName) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php b/app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php index e8c35ad46e2e5..083b4843c185a 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php +++ b/app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php @@ -13,7 +13,6 @@ * Introduces family of SQL assemblers * Each assembler populates SelectBuilder with config information * @see usage examples at \Magento\Analytics\ReportXml\QueryFactory - * @since 2.2.0 */ interface AssemblerInterface { @@ -23,7 +22,6 @@ interface AssemblerInterface * @param SelectBuilder $selectBuilder * @param array $queryConfig * @return SelectBuilder - * @since 2.2.0 */ public function assemble(SelectBuilder $selectBuilder, $queryConfig); } diff --git a/app/code/Magento/Analytics/ReportXml/DB/Assembler/FilterAssembler.php b/app/code/Magento/Analytics/ReportXml/DB/Assembler/FilterAssembler.php index bcd9e99319564..251c43f5e1b71 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/Assembler/FilterAssembler.php +++ b/app/code/Magento/Analytics/ReportXml/DB/Assembler/FilterAssembler.php @@ -14,19 +14,16 @@ * Class FilterAssembler * * Assembles WHERE conditions - * @since 2.2.0 */ class FilterAssembler implements AssemblerInterface { /** * @var ConditionResolver - * @since 2.2.0 */ private $conditionResolver; /** * @var NameResolver - * @since 2.2.0 */ private $nameResolver; @@ -35,7 +32,6 @@ class FilterAssembler implements AssemblerInterface * * @param ConditionResolver $conditionResolver * @param NameResolver $nameResolver - * @since 2.2.0 */ public function __construct( ConditionResolver $conditionResolver, @@ -51,7 +47,6 @@ public function __construct( * @param SelectBuilder $selectBuilder * @param array $queryConfig * @return SelectBuilder - * @since 2.2.0 */ public function assemble(SelectBuilder $selectBuilder, $queryConfig) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php b/app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php index 8b6f739e3ecdc..811119ace221b 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php +++ b/app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php @@ -13,25 +13,21 @@ /** * Assembles FROM condition - * @since 2.2.0 */ class FromAssembler implements AssemblerInterface { /** * @var NameResolver - * @since 2.2.0 */ private $nameResolver; /** * @var ColumnsResolver - * @since 2.2.0 */ private $columnsResolver; /** * @var ResourceConnection - * @since 2.2.0 */ private $resourceConnection; @@ -39,7 +35,6 @@ class FromAssembler implements AssemblerInterface * @param NameResolver $nameResolver * @param ColumnsResolver $columnsResolver * @param ResourceConnection $resourceConnection - * @since 2.2.0 */ public function __construct( NameResolver $nameResolver, @@ -57,7 +52,6 @@ public function __construct( * @param SelectBuilder $selectBuilder * @param array $queryConfig * @return SelectBuilder - * @since 2.2.0 */ public function assemble(SelectBuilder $selectBuilder, $queryConfig) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php b/app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php index ec83019c39c31..f3c6540a25171 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php +++ b/app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php @@ -16,31 +16,26 @@ * Class JoinAssembler * * Assembles JOIN conditions - * @since 2.2.0 */ class JoinAssembler implements AssemblerInterface { /** * @var ConditionResolver - * @since 2.2.0 */ private $conditionResolver; /** * @var NameResolver - * @since 2.2.0 */ private $nameResolver; /** * @var ColumnsResolver - * @since 2.2.0 */ private $columnsResolver; /** * @var ResourceConnection - * @since 2.2.0 */ private $resourceConnection; @@ -49,7 +44,6 @@ class JoinAssembler implements AssemblerInterface * @param ColumnsResolver $columnsResolver * @param NameResolver $nameResolver * @param ResourceConnection $resourceConnection - * @since 2.2.0 */ public function __construct( ConditionResolver $conditionResolver, @@ -69,7 +63,6 @@ public function __construct( * @param SelectBuilder $selectBuilder * @param array $queryConfig * @return SelectBuilder - * @since 2.2.0 */ public function assemble(SelectBuilder $selectBuilder, $queryConfig) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php b/app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php index 5b9279175b5ff..e6474d4c5dc6d 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php +++ b/app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php @@ -13,25 +13,21 @@ * Class ColumnsResolver * * Resolves columns names - * @since 2.2.0 */ class ColumnsResolver { /** * @var NameResolver - * @since 2.2.0 */ private $nameResolver; /** * @var ResourceConnection - * @since 2.2.0 */ private $resourceConnection; /** * @var \Magento\Framework\DB\Adapter\AdapterInterface - * @since 2.2.0 */ private $connection; @@ -40,7 +36,6 @@ class ColumnsResolver * * @param NameResolver $nameResolver * @param ResourceConnection $resourceConnection - * @since 2.2.0 */ public function __construct( NameResolver $nameResolver, @@ -54,7 +49,6 @@ public function __construct( * Returns connection * * @return \Magento\Framework\DB\Adapter\AdapterInterface - * @since 2.2.0 */ private function getConnection() { @@ -70,7 +64,6 @@ private function getConnection() * @param SelectBuilder $selectBuilder * @param array $entityConfig * @return array - * @since 2.2.0 */ public function getColumns(SelectBuilder $selectBuilder, $entityConfig) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php b/app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php index 96a7b0b95cafd..773b96959e794 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php +++ b/app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php @@ -13,13 +13,11 @@ * Class ConditionResolver * * Mapper for WHERE conditions - * @since 2.2.0 */ class ConditionResolver { /** * @var array - * @since 2.2.0 */ private $conditionMap = [ 'eq' => '%1$s = %2$s', @@ -39,20 +37,17 @@ class ConditionResolver /** * @var \Magento\Framework\DB\Adapter\AdapterInterface - * @since 2.2.0 */ private $connection; /** * @var ResourceConnection - * @since 2.2.0 */ private $resourceConnection; /** * ConditionResolver constructor. * @param ResourceConnection $resourceConnection - * @since 2.2.0 */ public function __construct( ResourceConnection $resourceConnection @@ -64,7 +59,6 @@ public function __construct( * Returns connection * * @return \Magento\Framework\DB\Adapter\AdapterInterface - * @since 2.2.0 */ private function getConnection() { @@ -80,7 +74,6 @@ private function getConnection() * @param string $condition * @param string $referencedEntity * @return mixed|null|string|\Zend_Db_Expr - * @since 2.2.0 */ private function getValue($condition, $referencedEntity) { @@ -114,7 +107,6 @@ private function getValue($condition, $referencedEntity) * @param array $condition * @param null|string $referencedEntity * @return string - * @since 2.2.0 */ private function getCondition(SelectBuilder $selectBuilder, $tableName, $condition, $referencedEntity = null) { @@ -141,7 +133,6 @@ private function getCondition(SelectBuilder $selectBuilder, $tableName, $conditi * @param string $aliasName * @param null|string $referencedAlias * @return array - * @since 2.2.0 */ public function getFilter(SelectBuilder $selectBuilder, $filterConfig, $aliasName, $referencedAlias = null) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/NameResolver.php b/app/code/Magento/Analytics/ReportXml/DB/NameResolver.php index fdea82ba25426..c9543002eb272 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/NameResolver.php +++ b/app/code/Magento/Analytics/ReportXml/DB/NameResolver.php @@ -9,7 +9,6 @@ * Class NameResolver * * Resolver for source names - * @since 2.2.0 */ class NameResolver { @@ -18,7 +17,6 @@ class NameResolver * * @param array $elementConfig * @return string - * @since 2.2.0 */ public function getName($elementConfig) { @@ -30,7 +28,6 @@ public function getName($elementConfig) * * @param array $elementConfig * @return string - * @since 2.2.0 */ public function getAlias($elementConfig) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php b/app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php index 1092d5fd1e4fc..21a641f0a71c7 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php +++ b/app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php @@ -13,19 +13,16 @@ * Class ReportValidator * * Validates report definitions by doing query to storage with limit 0 - * @since 2.2.0 */ class ReportValidator { /** * @var ConnectionFactory - * @since 2.2.0 */ private $connectionFactory; /** * @var QueryFactory - * @since 2.2.0 */ private $queryFactory; @@ -36,7 +33,6 @@ class ReportValidator * * @param ConnectionFactory $connectionFactory * @param QueryFactory $queryFactory - * @since 2.2.0 */ public function __construct(ConnectionFactory $connectionFactory, QueryFactory $queryFactory) { @@ -51,7 +47,6 @@ public function __construct(ConnectionFactory $connectionFactory, QueryFactory $ * @param SearchCriteriaInterface $criteria * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function validate($name, SearchCriteriaInterface $criteria = null) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php index bb37af94c9419..4e5a1940773b1 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php +++ b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php @@ -14,61 +14,51 @@ * * Responsible for Select object creation, works as a builder. Returns Select as result; * Used in SQL assemblers. - * @since 2.2.0 */ class SelectBuilder { /** * @var ResourceConnection - * @since 2.2.0 */ private $resourceConnection; /** * @var string - * @since 2.2.0 */ private $connectionName; /** * @var array - * @since 2.2.0 */ private $from; /** * @var array - * @since 2.2.0 */ private $group = []; /** * @var array - * @since 2.2.0 */ private $columns = []; /** * @var array - * @since 2.2.0 */ private $filters = []; /** * @var array - * @since 2.2.0 */ private $joins = []; /** * @var array - * @since 2.2.0 */ private $params = []; /** * @var array - * @since 2.2.0 */ private $having = []; @@ -76,7 +66,6 @@ class SelectBuilder * SelectBuilder constructor. * * @param ResourceConnection $resourceConnection - * @since 2.2.0 */ public function __construct( ResourceConnection $resourceConnection @@ -88,7 +77,6 @@ public function __construct( * Get join condition * * @return array - * @since 2.2.0 */ public function getJoins() { @@ -100,7 +88,6 @@ public function getJoins() * * @param array $joins * @return void - * @since 2.2.0 */ public function setJoins($joins) { @@ -111,7 +98,6 @@ public function setJoins($joins) * Get connection name * * @return string - * @since 2.2.0 */ public function getConnectionName() { @@ -123,7 +109,6 @@ public function getConnectionName() * * @param string $connectionName * @return void - * @since 2.2.0 */ public function setConnectionName($connectionName) { @@ -134,7 +119,6 @@ public function setConnectionName($connectionName) * Get columns * * @return array - * @since 2.2.0 */ public function getColumns() { @@ -146,7 +130,6 @@ public function getColumns() * * @param array $columns * @return void - * @since 2.2.0 */ public function setColumns($columns) { @@ -157,7 +140,6 @@ public function setColumns($columns) * Get filters * * @return array - * @since 2.2.0 */ public function getFilters() { @@ -169,7 +151,6 @@ public function getFilters() * * @param array $filters * @return void - * @since 2.2.0 */ public function setFilters($filters) { @@ -180,7 +161,6 @@ public function setFilters($filters) * Get from condition * * @return array - * @since 2.2.0 */ public function getFrom() { @@ -192,7 +172,6 @@ public function getFrom() * * @param array $from * @return void - * @since 2.2.0 */ public function setFrom($from) { @@ -205,7 +184,6 @@ public function setFrom($from) * @param Select $select * @param array $joinConfig * @return Select - * @since 2.2.0 */ private function processJoin(Select $select, $joinConfig) { @@ -227,7 +205,6 @@ private function processJoin(Select $select, $joinConfig) * Creates Select object * * @return Select - * @since 2.2.0 */ public function create() { @@ -251,7 +228,6 @@ public function create() * Returns group * * @return array - * @since 2.2.0 */ public function getGroup() { @@ -263,7 +239,6 @@ public function getGroup() * * @param array $group * @return void - * @since 2.2.0 */ public function setGroup($group) { @@ -274,7 +249,6 @@ public function setGroup($group) * Get parameters * * @return array - * @since 2.2.0 */ public function getParams() { @@ -286,7 +260,6 @@ public function getParams() * * @param array $params * @return void - * @since 2.2.0 */ public function setParams($params) { @@ -297,7 +270,6 @@ public function setParams($params) * Get having condition * * @return array - * @since 2.2.0 */ public function getHaving() { @@ -309,7 +281,6 @@ public function getHaving() * * @param array $having * @return void - * @since 2.2.0 */ public function setHaving($having) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php index 1866d9282c1e9..1d88d4618efc5 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php +++ b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php @@ -9,7 +9,6 @@ /** * Factory class for @see \Magento\Analytics\ReportXml\DB\SelectBuilder - * @since 2.2.0 */ class SelectBuilderFactory { @@ -17,7 +16,6 @@ class SelectBuilderFactory * Object Manager instance * * @var ObjectManagerInterface - * @since 2.2.0 */ private $objectManager; @@ -25,7 +23,6 @@ class SelectBuilderFactory * SelectBuilderFactory constructor. * * @param ObjectManagerInterface $objectManager - * @since 2.2.0 */ public function __construct( ObjectManagerInterface $objectManager @@ -38,7 +35,6 @@ public function __construct( * * @param array $data * @return SelectBuilder - * @since 2.2.0 */ public function create(array $data = []) { diff --git a/app/code/Magento/Analytics/ReportXml/IteratorFactory.php b/app/code/Magento/Analytics/ReportXml/IteratorFactory.php index 195fad845623f..a196cef8b66dc 100644 --- a/app/code/Magento/Analytics/ReportXml/IteratorFactory.php +++ b/app/code/Magento/Analytics/ReportXml/IteratorFactory.php @@ -10,19 +10,16 @@ /** * Class IteratorFactory - * @since 2.2.0 */ class IteratorFactory { /** * @var ObjectManagerInterface - * @since 2.2.0 */ private $objectManager; /** * @var string - * @since 2.2.0 */ private $defaultIteratorName; @@ -31,7 +28,6 @@ class IteratorFactory * * @param ObjectManagerInterface $objectManager * @param string $defaultIteratorName - * @since 2.2.0 */ public function __construct( ObjectManagerInterface $objectManager, @@ -52,7 +48,6 @@ public function __construct( * @param \Traversable $result * @param string|null $iteratorName * @return \IteratorIterator - * @since 2.2.0 */ public function create(\Traversable $result, $iteratorName = null) { diff --git a/app/code/Magento/Analytics/ReportXml/Query.php b/app/code/Magento/Analytics/ReportXml/Query.php index 7e464a5ad46d1..46ec2fb494183 100644 --- a/app/code/Magento/Analytics/ReportXml/Query.php +++ b/app/code/Magento/Analytics/ReportXml/Query.php @@ -11,31 +11,26 @@ * Class Query * * Query object, contains SQL statement, information about connection, query arguments - * @since 2.2.0 */ class Query implements \JsonSerializable { /** * @var Select - * @since 2.2.0 */ private $select; /** * @var \Magento\Analytics\ReportXml\SelectHydrator - * @since 2.2.0 */ private $selectHydrator; /** * @var string - * @since 2.2.0 */ private $connectionName; /** * @var array - * @since 2.2.0 */ private $config; @@ -46,7 +41,6 @@ class Query implements \JsonSerializable * @param SelectHydrator $selectHydrator * @param string $connectionName * @param array $config - * @since 2.2.0 */ public function __construct( Select $select, @@ -62,7 +56,6 @@ public function __construct( /** * @return Select - * @since 2.2.0 */ public function getSelect() { @@ -71,7 +64,6 @@ public function getSelect() /** * @return string - * @since 2.2.0 */ public function getConnectionName() { @@ -80,7 +72,6 @@ public function getConnectionName() /** * @return array - * @since 2.2.0 */ public function getConfig() { diff --git a/app/code/Magento/Analytics/ReportXml/QueryFactory.php b/app/code/Magento/Analytics/ReportXml/QueryFactory.php index 37e6609553023..8ed7e767b28b3 100644 --- a/app/code/Magento/Analytics/ReportXml/QueryFactory.php +++ b/app/code/Magento/Analytics/ReportXml/QueryFactory.php @@ -14,43 +14,36 @@ * * Creates Query object according to configuration * Factory for @see \Magento\Analytics\ReportXml\Query - * @since 2.2.0 */ class QueryFactory { /** * @var Config - * @since 2.2.0 */ private $config; /** * @var SelectBuilderFactory - * @since 2.2.0 */ private $selectBuilderFactory; /** * @var DB\Assembler\AssemblerInterface[] - * @since 2.2.0 */ private $assemblers; /** * @var CacheInterface - * @since 2.2.0 */ private $queryCache; /** * @var ObjectManagerInterface - * @since 2.2.0 */ private $objectManager; /** * @var SelectHydrator - * @since 2.2.0 */ private $selectHydrator; @@ -63,7 +56,6 @@ class QueryFactory * @param SelectBuilderFactory $selectBuilderFactory * @param Config $config * @param array $assemblers - * @since 2.2.0 */ public function __construct( CacheInterface $queryCache, @@ -86,7 +78,6 @@ public function __construct( * * @param string $queryConfig * @return string - * @since 2.2.0 */ private function getQueryConnectionName($queryConfig) { @@ -102,7 +93,6 @@ private function getQueryConnectionName($queryConfig) * * @param string $queryName * @return Query - * @since 2.2.0 */ private function constructQuery($queryName) { @@ -129,7 +119,6 @@ private function constructQuery($queryName) * * @param string $queryName * @return Query - * @since 2.2.0 */ public function create($queryName) { diff --git a/app/code/Magento/Analytics/ReportXml/ReportProvider.php b/app/code/Magento/Analytics/ReportXml/ReportProvider.php index 4edd1100c5325..3ebe5941108bc 100644 --- a/app/code/Magento/Analytics/ReportXml/ReportProvider.php +++ b/app/code/Magento/Analytics/ReportXml/ReportProvider.php @@ -12,25 +12,21 @@ * Class ReportProvider * * Providers for reports data - * @since 2.2.0 */ class ReportProvider { /** * @var QueryFactory - * @since 2.2.0 */ private $queryFactory; /** * @var ConnectionFactory - * @since 2.2.0 */ private $connectionFactory; /** * @var IteratorFactory - * @since 2.2.0 */ private $iteratorFactory; @@ -40,7 +36,6 @@ class ReportProvider * @param QueryFactory $queryFactory * @param ConnectionFactory $connectionFactory * @param IteratorFactory $iteratorFactory - * @since 2.2.0 */ public function __construct( QueryFactory $queryFactory, @@ -58,7 +53,6 @@ public function __construct( * * @param Query $query * @return string|null - * @since 2.2.0 */ private function getIteratorName(Query $query) { @@ -71,7 +65,6 @@ private function getIteratorName(Query $query) * * @param string $name * @return \IteratorIterator - * @since 2.2.0 */ public function getReport($name) { diff --git a/app/code/Magento/Analytics/ReportXml/SelectHydrator.php b/app/code/Magento/Analytics/ReportXml/SelectHydrator.php index 9dd0f8327dd14..02cde2fd0598d 100644 --- a/app/code/Magento/Analytics/ReportXml/SelectHydrator.php +++ b/app/code/Magento/Analytics/ReportXml/SelectHydrator.php @@ -12,7 +12,6 @@ /** * Class SelectHydrator - * @since 2.2.0 */ class SelectHydrator { @@ -20,7 +19,6 @@ class SelectHydrator * Array of supported Select parts * * @var array - * @since 2.2.0 */ private $predefinedSelectParts = [ @@ -39,19 +37,16 @@ class SelectHydrator /** * @var array - * @since 2.2.0 */ private $selectParts; /** * @var ResourceConnection - * @since 2.2.0 */ private $resourceConnection; /** * @var ObjectManagerInterface - * @since 2.2.0 */ private $objectManager; @@ -59,7 +54,6 @@ class SelectHydrator * @param ResourceConnection $resourceConnection * @param ObjectManagerInterface $objectManager * @param array $selectParts - * @since 2.2.0 */ public function __construct( ResourceConnection $resourceConnection, @@ -73,7 +67,6 @@ public function __construct( /** * @return array - * @since 2.2.0 */ private function getSelectParts() { @@ -86,7 +79,6 @@ private function getSelectParts() * @param Select $select * @return array * @throws \Zend_Db_Select_Exception - * @since 2.2.0 */ public function extract(Select $select) { @@ -100,7 +92,6 @@ public function extract(Select $select) /** * @param array $selectParts * @return Select - * @since 2.2.0 */ public function recreate(array $selectParts) { @@ -124,7 +115,6 @@ public function recreate(array $selectParts) * @param Select $select * @param array $selectParts * @return Select - * @since 2.2.0 */ private function processColumns(Select $select, array &$selectParts) { diff --git a/app/code/Magento/Analytics/Setup/InstallData.php b/app/code/Magento/Analytics/Setup/InstallData.php index 5a67a6d5e6765..aaa619bbb0caa 100644 --- a/app/code/Magento/Analytics/Setup/InstallData.php +++ b/app/code/Magento/Analytics/Setup/InstallData.php @@ -13,7 +13,6 @@ /** * @codeCoverageIgnore - * @since 2.2.0 */ class InstallData implements InstallDataInterface { @@ -21,7 +20,6 @@ class InstallData implements InstallDataInterface /** * {@inheritdoc} * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - * @since 2.2.0 */ public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) { diff --git a/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php b/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php index eada5011a933f..87f5c7c5bc4fd 100644 --- a/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php +++ b/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php @@ -12,7 +12,6 @@ /** * Class which serves as stub for degenerated UI component. - * @since 2.2.0 */ class DummyDataProvider implements DataProviderInterface { @@ -20,7 +19,6 @@ class DummyDataProvider implements DataProviderInterface * Search result object. * * @var SearchResultInterface - * @since 2.2.0 */ private $searchResult; @@ -28,7 +26,6 @@ class DummyDataProvider implements DataProviderInterface * Search criteria object. * * @var SearchCriteriaInterface - * @since 2.2.0 */ private $searchCriteria; @@ -36,7 +33,6 @@ class DummyDataProvider implements DataProviderInterface * Data collection. * * @var Collection - * @since 2.2.0 */ private $collection; @@ -44,7 +40,6 @@ class DummyDataProvider implements DataProviderInterface * Own name of this provider. * * @var string - * @since 2.2.0 */ private $name; @@ -52,7 +47,6 @@ class DummyDataProvider implements DataProviderInterface * Provider configuration data. * * @var array - * @since 2.2.0 */ private $data; @@ -62,7 +56,6 @@ class DummyDataProvider implements DataProviderInterface * @param SearchCriteriaInterface $searchCriteria * @param Collection $collection * @param array $data - * @since 2.2.0 */ public function __construct( $name, @@ -82,7 +75,6 @@ public function __construct( * Get Data Provider name * * @return string - * @since 2.2.0 */ public function getName() { @@ -93,7 +85,6 @@ public function getName() * Get config data * * @return mixed - * @since 2.2.0 */ public function getConfigData() { @@ -106,7 +97,6 @@ public function getConfigData() * @param mixed $config * * @return bool - * @since 2.2.0 */ public function setConfigData($config) { @@ -117,7 +107,6 @@ public function setConfigData($config) /** * @return array - * @since 2.2.0 */ public function getMeta() { @@ -130,7 +119,6 @@ public function getMeta() * * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function getFieldMetaInfo($fieldSetName, $fieldName) { @@ -144,7 +132,6 @@ public function getFieldMetaInfo($fieldSetName, $fieldName) * * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function getFieldSetMetaInfo($fieldSetName) { @@ -156,7 +143,6 @@ public function getFieldSetMetaInfo($fieldSetName) * * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function getFieldsMetaInfo($fieldSetName) { @@ -167,7 +153,6 @@ public function getFieldsMetaInfo($fieldSetName) * Get primary field name * * @return string - * @since 2.2.0 */ public function getPrimaryFieldName() { @@ -178,7 +163,6 @@ public function getPrimaryFieldName() * Get field name in request * * @return string - * @since 2.2.0 */ public function getRequestFieldName() { @@ -189,7 +173,6 @@ public function getRequestFieldName() * Get data * * @return mixed - * @since 2.2.0 */ public function getData() { @@ -203,7 +186,6 @@ public function getData() * * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function addFilter(\Magento\Framework\Api\Filter $filter) { @@ -217,7 +199,6 @@ public function addFilter(\Magento\Framework\Api\Filter $filter) * * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function addOrder($field, $direction) { @@ -231,7 +212,6 @@ public function addOrder($field, $direction) * * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function setLimit($offset, $size) { @@ -241,7 +221,6 @@ public function setLimit($offset, $size) * Returns search criteria * * @return SearchCriteriaInterface - * @since 2.2.0 */ public function getSearchCriteria() { @@ -250,7 +229,6 @@ public function getSearchCriteria() /** * @return SearchResultInterface - * @since 2.2.0 */ public function getSearchResult() { From a1137d98a064ea23f5c86538d645245a5cef3218 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Thu, 5 Oct 2017 11:06:25 -0500 Subject: [PATCH 016/194] MAGETWO-80474: Update Advanced Reporting Configuration Page --- .../Block/Adminhtml/System/Config/Vertical.php | 5 ++++- .../System/Config/AdditionalCommentTest.php | 15 ++++++++------- .../System/Config/CollectionTimeLabelTest.php | 16 +++++++++------- .../Config/SubscriptionStatusLabelTest.php | 17 ++++++++--------- .../Adminhtml/System/Config/VerticalTest.php | 15 ++++++++------- .../Magento/Analytics/etc/adminhtml/system.xml | 4 ++-- 6 files changed, 39 insertions(+), 33 deletions(-) diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php index b7ec114e69563..6ba95bf76cde3 100644 --- a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php @@ -6,11 +6,12 @@ namespace Magento\Analytics\Block\Adminhtml\System\Config; /** - * Provides select with industry information + * Provides vertical select with additional information and style customization */ class Vertical extends \Magento\Config\Block\System\Config\Form\Field { /** + * @inheritdoc * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @return string */ @@ -22,6 +23,8 @@ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $ele } /** + * Decorates row HTML for custom element style + * * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @param string $html * @return string diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php index 744ba7466e593..cbf06264096ac 100644 --- a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php @@ -9,6 +9,7 @@ use Magento\Backend\Block\Template\Context; use Magento\Framework\Data\Form; use Magento\Framework\Data\Form\Element\AbstractElement; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; class AdditionalCommentTest extends \PHPUnit\Framework\TestCase { @@ -32,9 +33,6 @@ class AdditionalCommentTest extends \PHPUnit\Framework\TestCase */ private $formMock; - /** - * @return void - */ protected function setUp() { $this->abstractElementMock = $this->getMockBuilder(AbstractElement::class) @@ -48,12 +46,15 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->additionalComment = new AdditionalComment($this->contextMock); + $objectManager = new ObjectManager($this); + $this->additionalComment = $objectManager->getObject( + AdditionalComment::class, + [ + 'context' => $this->contextMock + ] + ); } - /** - * @return void - */ public function testRender() { $this->abstractElementMock->setForm($this->formMock); diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php index 74fbbf2e78a40..a652cf6b3d548 100644 --- a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php @@ -10,6 +10,7 @@ use Magento\Framework\Data\Form; use Magento\Framework\Data\Form\Element\AbstractElement; use Magento\Framework\Stdlib\DateTime\TimezoneInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; class CollectionTimeLabelTest extends \PHPUnit\Framework\TestCase { @@ -33,9 +34,6 @@ class CollectionTimeLabelTest extends \PHPUnit\Framework\TestCase */ private $abstractElementMock; - /** - * @return void - */ protected function setUp() { $this->abstractElementMock = $this->getMockBuilder(AbstractElement::class) @@ -55,12 +53,16 @@ protected function setUp() $this->contextMock->expects($this->any()) ->method('getLocaleDate') ->willReturn($this->timeZoneMock); - $this->collectionTimeLabel = new CollectionTimeLabel($this->contextMock); + + $objectManager = new ObjectManager($this); + $this->collectionTimeLabel = $objectManager->getObject( + CollectionTimeLabel::class, + [ + 'context' => $this->contextMock + ] + ); } - /** - * @return void - */ public function testRender() { $timeZone = "America/New_York"; diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php index 04728c403a861..09e753e4ac8aa 100644 --- a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php @@ -10,6 +10,7 @@ use Magento\Backend\Block\Template\Context; use Magento\Framework\Data\Form; use Magento\Framework\Data\Form\Element\AbstractElement; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; /** * Class SignupTest @@ -41,9 +42,6 @@ class SubscriptionStatusLabelTest extends \PHPUnit\Framework\TestCase */ private $formMock; - /** - * @return void - */ protected function setUp() { $this->subscriptionStatusProviderMock = $this->getMockBuilder(SubscriptionStatusProvider::class) @@ -60,15 +58,16 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->subscriptionStatusLabel = new SubscriptionStatusLabel( - $this->contextMock, - $this->subscriptionStatusProviderMock + $objectManager = new ObjectManager($this); + $this->subscriptionStatusLabel = $objectManager->getObject( + SubscriptionStatusLabel::class, + [ + 'context' => $this->contextMock, + 'subscriptionStatusProvider' => $this->subscriptionStatusProviderMock + ] ); } - /** - * @return void - */ public function testRender() { $this->abstractElementMock->setForm($this->formMock); diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php index 331b487e5dd9d..abce48c36c86a 100644 --- a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php @@ -9,6 +9,7 @@ use Magento\Backend\Block\Template\Context; use Magento\Framework\Data\Form; use Magento\Framework\Data\Form\Element\AbstractElement; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; class VerticalTest extends \PHPUnit\Framework\TestCase { @@ -32,9 +33,6 @@ class VerticalTest extends \PHPUnit\Framework\TestCase */ private $formMock; - /** - * @return void - */ protected function setUp() { $this->abstractElementMock = $this->getMockBuilder(AbstractElement::class) @@ -48,12 +46,15 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->vertical = new Vertical($this->contextMock); + $objectManager = new ObjectManager($this); + $this->vertical = $objectManager->getObject( + Vertical::class, + [ + 'context' => $this->contextMock + ] + ); } - /** - * @return void - */ public function testRender() { $this->abstractElementMock->setForm($this->formMock); diff --git a/app/code/Magento/Analytics/etc/adminhtml/system.xml b/app/code/Magento/Analytics/etc/adminhtml/system.xml index 3d87c24176c81..c3bf5c4b11d2f 100644 --- a/app/code/Magento/Analytics/etc/adminhtml/system.xml +++ b/app/code/Magento/Analytics/etc/adminhtml/system.xml @@ -28,7 +28,7 @@ Magento\Analytics\Block\Adminhtml\System\Config\CollectionTimeLabel Magento\Analytics\Model\Config\Backend\CollectionTime
- + Industry Data In order to personalize your Advanced Reporting experience, please select your industry. @@ -36,7 +36,7 @@ Magento\Analytics\Model\Config\Backend\Vertical Magento\Analytics\Block\Adminhtml\System\Config\Vertical - + Learn more about Date: Thu, 5 Oct 2017 11:44:44 -0500 Subject: [PATCH 017/194] MAGETWO-80474: Update Advanced Reporting Configuration Page --- .../Analytics/Block/Adminhtml/System/Config/Vertical.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php index 6ba95bf76cde3..99606e10f99d9 100644 --- a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php @@ -12,8 +12,6 @@ class Vertical extends \Magento\Config\Block\System\Config\Form\Field { /** * @inheritdoc - * @param \Magento\Framework\Data\Form\Element\AbstractElement $element - * @return string */ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) { From 7ddbd2b65762074b88c39c959247f9292a5d63a9 Mon Sep 17 00:00:00 2001 From: Joan He Date: Thu, 5 Oct 2017 14:45:55 -0500 Subject: [PATCH 018/194] MAGETWO-80479: Update existing Advanced Reporting tests - Remove obsolete tests --- .../AssertConfigAnalyticsRestored.php | 54 ------------------- .../AssertDisableReportingInPopup.php | 49 ----------------- .../AssertEnableReportingInPopup.php | 42 --------------- .../Constraint/AssertSkipReportingInPopup.php | 42 --------------- .../AssertSubscriptionPopupNotExist.php | 39 -------------- .../app/Magento/Analytics/Test/etc/di.xml | 25 --------- 6 files changed, 251 deletions(-) delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php deleted file mode 100644 index e624b49ff38dc..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php +++ /dev/null @@ -1,54 +0,0 @@ -run(); - - $configAnalytics->getAnalyticsForm()->analyticsToggle(); - $configAnalytics->getAnalyticsForm()->setAnalyticsVertical($vertical); - $configAnalytics->getAnalyticsForm()->saveConfig(); - - \PHPUnit_Framework_Assert::assertTrue( - $systemConfigPage->getMessagesBlock()->assertSuccessMessage(), - 'Sending data to the Analytics is not saved.' - ); - } - - /** - * Returns a string representation of the object. - * - * @return string - */ - public function toString() - { - return 'Sending data to the Analytics is saved.'; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php deleted file mode 100644 index de1facb47230b..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php +++ /dev/null @@ -1,49 +0,0 @@ -open(); - $dashboard->getSubscriptionBlock()->enableCheckbox(); - $dashboard->getSubscriptionBlock()->declineAdvancedReporting(); - $dashboard->getModalBlock()->dismissWarning(); - $dashboard->getSubscriptionBlock()->declineAdvancedReporting(); - \PHPUnit_Framework_Assert::assertFalse( - $dashboard->getSubscriptionBlock()->isVisible(), - 'Advanced Reporting was not disabled' - ); - $dashboard->getModalBlock()->acceptWarning(); - \PHPUnit_Framework_Assert::assertFalse( - $dashboard->getModalBlock()->isVisible(), - 'Advanced Reporting disabling was not confirmed' - ); - } - - /** - * Returns a string representation of the object. - * - * @return string - */ - public function toString() - { - return 'Advanced Reporting was disabled'; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php deleted file mode 100644 index 9205ee89f0913..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php +++ /dev/null @@ -1,42 +0,0 @@ -open(); - $dashboard->getSubscriptionBlock()->enableCheckbox(); - $dashboard->getSubscriptionBlock()->acceptAdvancedReporting(); - \PHPUnit_Framework_Assert::assertFalse( - $dashboard->getSubscriptionBlock()->isVisible(), - 'Advanced Reporting was not enabled' - ); - } - - /** - * Returns a string representation of the object. - * - * @return string - */ - public function toString() - { - return 'Advanced Reporting was enabled'; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php deleted file mode 100644 index ddb3593537ad8..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php +++ /dev/null @@ -1,42 +0,0 @@ -open(); - $dashboard->getSubscriptionBlock()->disableCheckbox(); - $dashboard->getSubscriptionBlock()->skipAdvancedReporting(); - \PHPUnit_Framework_Assert::assertFalse( - $dashboard->getSubscriptionBlock()->isVisible(), - 'Advanced Reporting was not skipped' - ); - } - - /** - * Returns a string representation of the object. - * - * @return string - */ - public function toString() - { - return 'Advanced Reporting was skipped'; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php deleted file mode 100644 index c2bb48f4bb2ec..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php +++ /dev/null @@ -1,39 +0,0 @@ -getSubscriptionBlock()->isVisible(), - "Subscription form is visible on dashboard." - ); - } - - /** - * Returns a string representation of the object. - * - * @return string - */ - public function toString() - { - return "Subscription form is absent on dashboard."; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml index 74b10cca43c1f..cc113f1768e2e 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml @@ -13,11 +13,6 @@ - - - S1 - - S1 @@ -28,24 +23,4 @@ S1 - - - S1 - - - - - S1 - - - - - S1 - - - - - S1 - - From 0c127edb4ab39cf296b8884bf588566c7f8148ad Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Thu, 5 Oct 2017 15:14:32 -0500 Subject: [PATCH 019/194] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- .../Model/Condition/CanViewNotification.php | 18 ++- .../Analytics/Model/NotificationFlag.php | 75 +++++++++++ .../Analytics/Model/NotificationTime.php | 85 ------------ .../Condition/CanViewNotificationTest.php | 22 +-- .../Enabled/SubscriptionHandlerTest.php | 16 --- .../Test/Unit/Model/NotificationFlagTest.php | 107 +++++++++++++++ .../Test/Unit/Model/NotificationTimeTest.php | 126 ------------------ app/code/Magento/Analytics/etc/module.xml | 1 - .../layout/adminhtml_dashboard_index.xml | 2 +- .../web/css/source/_module.less | 6 +- .../web/images/advanced-reporting-badge.svg | 7 - .../web/images/analytics-icon.svg | 84 ++++++++++++ .../Mtf/App/State/NotificationTimeHandler.php | 56 -------- .../app/Magento/Analytics/Test/etc/di.xml | 22 --- .../Setup/Test/TestCase/UpgradeSystemTest.php | 13 -- .../js/modal/modal-component.test.js | 126 ------------------ 16 files changed, 289 insertions(+), 477 deletions(-) create mode 100644 app/code/Magento/Analytics/Model/NotificationFlag.php delete mode 100644 app/code/Magento/Analytics/Model/NotificationTime.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php delete mode 100644 app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php delete mode 100644 app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/advanced-reporting-badge.svg create mode 100644 app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/analytics-icon.svg delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php delete mode 100644 dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php index 88bc50e622f01..e66b9fa2d722d 100644 --- a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -6,7 +6,7 @@ namespace Magento\Analytics\Model\Condition; use Magento\Framework\View\Layout\Condition\VisibilityConditionInterface; -use Magento\Analytics\Model\NotificationTime; +use Magento\Analytics\Model\NotificationFlag; /** * Class CanViewNotification @@ -22,19 +22,19 @@ class CanViewNotification implements VisibilityConditionInterface const NAME = 'can_view_notification'; /** - * @var NotificationTime + * @var NotificationFlag */ - private $notificationTime; + private $notificationFlag; /** * CanViewNotification constructor. * - * @param NotificationTime $notificationTime + * @param NotificationFlag $notificationFlag */ public function __construct( - NotificationTime $notificationTime + NotificationFlag $notificationFlag ) { - $this->notificationTime = $notificationTime; + $this->notificationFlag = $notificationFlag; } /** @@ -44,13 +44,11 @@ public function __construct( */ public function isVisible(array $arguments) { - $lastNotificationTime = $this->notificationTime->getLastTimeNotificationForCurrentUser(); - - if ($lastNotificationTime) { + if ($this->notificationFlag->hasNotificationValueForCurrentUser()) { return false; } - return $this->notificationTime->storeLastTimeNotificationForCurrentUser(); + return $this->notificationFlag->storeNotificationValueForCurrentUser(); } /** diff --git a/app/code/Magento/Analytics/Model/NotificationFlag.php b/app/code/Magento/Analytics/Model/NotificationFlag.php new file mode 100644 index 0000000000000..7f282934d6d28 --- /dev/null +++ b/app/code/Magento/Analytics/Model/NotificationFlag.php @@ -0,0 +1,75 @@ +flagManager = $flagManager; + $this->session = $session; + } + + /** + * Stores flag to indicate the user was notified about Analytic services + * + * @return bool + */ + public function storeNotificationValueForCurrentUser() + { + $flagCode = self::NOTIFICATION_SEEN . $this->session->getUser()->getId(); + return $this->flagManager->saveFlag($flagCode, 1); + } + + /** + * Returns the flag data if the user was notified about Analytic services + * + * @return bool + */ + public function hasNotificationValueForCurrentUser() + { + return $this->flagManager->getFlagData(self::NOTIFICATION_SEEN . $this->session->getUser()->getId()); + } + + /** + * Remove the notification seen flag + * + * @return bool + */ + public function unsetNotificationValueForCurrentUser() + { + return $this->flagManager->deleteFlag(self::NOTIFICATION_SEEN . $this->session->getUser()->getId()); + } +} diff --git a/app/code/Magento/Analytics/Model/NotificationTime.php b/app/code/Magento/Analytics/Model/NotificationTime.php deleted file mode 100644 index c3ebf52da4b99..0000000000000 --- a/app/code/Magento/Analytics/Model/NotificationTime.php +++ /dev/null @@ -1,85 +0,0 @@ -flagManager = $flagManager; - $this->userContext = $userContext; - $this->dateTimeFactory = $dateTimeFactory; - } - - /** - * Stores last notification time - * - * @return bool - */ - public function storeLastTimeNotificationForCurrentUser() - { - $flagCode = self::NOTIFICATION_TIME . $this->userContext->getUserId(); - $dateTime = $this->dateTimeFactory->create(); - return $this->flagManager->saveFlag($flagCode, $dateTime->getTimestamp()); - } - - /** - * Returns last time when merchant was notified about Analytic services - * - * @return int - */ - public function getLastTimeNotificationForCurrentUser() - { - return $this->flagManager->getFlagData(self::NOTIFICATION_TIME . $this->userContext->getUserId()); - } - - /** - * Remove last notification time flag. - * - * @return bool - */ - public function unsetLastTimeNotificationValueForCurrentUser() - { - return $this->flagManager->deleteFlag(self::NOTIFICATION_TIME . $this->userContext->getUserId()); - } -} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index b12325a0ee511..e7eafcdbe7024 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -8,7 +8,7 @@ use Magento\Analytics\Model\Condition\CanViewNotification; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Analytics\Model\NotificationTime; +use Magento\Analytics\Model\NotificationFlag; /** * Class CanViewNotificationTest @@ -16,9 +16,9 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase { /** - * @var NotificationTime|\PHPUnit_Framework_MockObject_MockObject + * @var NotificationFlag|\PHPUnit_Framework_MockObject_MockObject */ - private $notificationTimeMock; + private $notificationFlagMock; /** * @var CanViewNotification @@ -27,33 +27,33 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase public function setUp() { - $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) + $this->notificationFlagMock = $this->getMockBuilder(NotificationFlag::class) ->disableOriginalConstructor() ->getMock(); $objectManager = new ObjectManager($this); $this->canViewNotification = $objectManager->getObject( CanViewNotification::class, [ - 'notificationTime' => $this->notificationTimeMock + 'notificationFlag' => $this->notificationFlagMock ] ); } public function testUserShouldSeeNotification() { - $this->notificationTimeMock->expects($this->once()) - ->method('getLastTimeNotificationForCurrentUser') + $this->notificationFlagMock->expects($this->once()) + ->method('hasNotificationValueForCurrentUser') ->willReturn(false); - $this->notificationTimeMock->expects($this->once()) - ->method('storeLastTimeNotificationForCurrentUser') + $this->notificationFlagMock->expects($this->once()) + ->method('storeNotificationValueForCurrentUser') ->willReturn(true); $this->assertTrue($this->canViewNotification->isVisible([])); } public function testUserShouldNotSeeNotification() { - $this->notificationTimeMock->expects($this->once()) - ->method('getLastTimeNotificationForCurrentUser') + $this->notificationFlagMock->expects($this->once()) + ->method('hasNotificationValueForCurrentUser') ->willReturn(true); $this->assertFalse($this->canViewNotification->isVisible([])); } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php index ff3b807e5d8c5..82aa4dc72dfe0 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php @@ -9,7 +9,6 @@ use Magento\Analytics\Model\AnalyticsToken; use Magento\Analytics\Model\Config\Backend\CollectionTime; use Magento\Analytics\Model\Config\Backend\Enabled\SubscriptionHandler; -use Magento\Analytics\Model\NotificationTime; use Magento\Framework\App\Config\Storage\WriterInterface; use Magento\Framework\FlagManager; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; @@ -49,9 +48,6 @@ class SubscriptionHandlerTest extends \PHPUnit\Framework\TestCase */ private $subscriptionHandler; - /** - * @return void - */ protected function setUp() { $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) @@ -79,9 +75,6 @@ protected function setUp() ); } - /** - * @return void - */ public function testProcessEnabledTokenExist() { $this->tokenMock @@ -99,9 +92,6 @@ public function testProcessEnabledTokenExist() ); } - /** - * @return void - */ public function testProcessEnabledTokenDoesNotExist() { $this->tokenMock @@ -122,9 +112,6 @@ public function testProcessEnabledTokenDoesNotExist() ); } - /** - * @return void - */ public function testProcessDisabledTokenDoesNotExist() { $this->configWriterMock @@ -145,9 +132,6 @@ public function testProcessDisabledTokenDoesNotExist() ); } - /** - * @return void - */ public function testProcessDisabledTokenExists() { $this->configWriterMock diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php new file mode 100644 index 0000000000000..94816cb0965c5 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php @@ -0,0 +1,107 @@ +userId = 1; + + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->sessionMock = $this->getMockBuilder(Session::class) + ->disableOriginalConstructor() + ->setMethods(['getUser', 'getId']) + ->getMock(); + $objectManagerHelper = new ObjectManagerHelper($this); + $this->notificationFlag = $objectManagerHelper->getObject( + NotificationFlag::class, + [ + 'flagManager' => $this->flagManagerMock, + 'session' => $this->sessionMock + ] + ); + } + + public function testStoreNotificationValueForCurrentUser() + { + $this->sessionMock->expects($this->once()) + ->method('getUser') + ->willReturnSelf(); + $this->sessionMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + $this->flagManagerMock + ->expects($this->once()) + ->method('saveFlag') + ->with(NotificationFlag::NOTIFICATION_SEEN . $this->userId, 1) + ->willReturn(true); + $this->assertTrue($this->notificationFlag->storeNotificationValueForCurrentUser()); + } + + public function testHasNotificationValueForCurrentUser() + { + $this->sessionMock->expects($this->once()) + ->method('getUser') + ->willReturnSelf(); + $this->sessionMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + $this->flagManagerMock + ->expects($this->once()) + ->method('getFlagData') + ->with(NotificationFlag::NOTIFICATION_SEEN . $this->userId) + ->willReturn(true); + $this->assertTrue($this->notificationFlag->hasNotificationValueForCurrentUser()); + } + + public function testUnsetNotificationValueForCurrentUser() + { + $this->sessionMock->expects($this->once()) + ->method('getUser') + ->willReturnSelf(); + $this->sessionMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + $this->flagManagerMock + ->expects($this->once()) + ->method('deleteFlag') + ->with(NotificationFlag::NOTIFICATION_SEEN . $this->userId) + ->willReturn(true); + $this->assertTrue($this->notificationFlag->unsetNotificationValueForCurrentUser()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php deleted file mode 100644 index e60407f9bf8dd..0000000000000 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php +++ /dev/null @@ -1,126 +0,0 @@ -value = 10005000; - $this->userId = 1; - - $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) - ->disableOriginalConstructor() - ->getMock(); - $this->userContextInterfaceMock = $this->getMockBuilder(UserContextInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->dateTimeFactoryMock = $this->getMockBuilder(DateTimeFactory::class) - ->getMock(); - $this->dateTimeMock = $this->getMockBuilder(\DateTime::class) - ->getMock(); - $objectManagerHelper = new ObjectManagerHelper($this); - $this->notificationTime = $objectManagerHelper->getObject( - NotificationTime::class, - [ - 'flagManager' => $this->flagManagerMock, - 'userContext' => $this->userContextInterfaceMock, - 'dateTimeFactory' => $this->dateTimeFactoryMock - ] - ); - } - - public function testStoreLastTimeNotificationForCurrentUser() - { - $this->userContextInterfaceMock->expects($this->once()) - ->method("getUserId") - ->willReturn(1); - $this->dateTimeFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->dateTimeMock); - $this->dateTimeMock->expects($this->once()) - ->method('getTimestamp') - ->willReturn(10005000); - - $this->flagManagerMock - ->expects($this->once()) - ->method('saveFlag') - ->with(NotificationTime::NOTIFICATION_TIME . $this->userId, $this->value) - ->willReturn(true); - $this->assertTrue($this->notificationTime->storeLastTimeNotificationForCurrentUser()); - } - - public function testGetLastTimeNotificationForCurrentUser() - { - $this->userContextInterfaceMock->expects($this->once()) - ->method("getUserId") - ->willReturn(1); - $this->flagManagerMock - ->expects($this->once()) - ->method('getFlagData') - ->with(NotificationTime::NOTIFICATION_TIME . $this->userId) - ->willReturn(true); - $this->assertEquals($this->value, $this->notificationTime->getLastTimeNotificationForCurrentUser()); - } - - public function testUnsetLastTimeNotificationValueForCurrentUser() - { - $this->userContextInterfaceMock->expects($this->once()) - ->method("getUserId") - ->willReturn(1); - $this->flagManagerMock - ->expects($this->once()) - ->method('deleteFlag') - ->with(NotificationTime::NOTIFICATION_TIME . $this->userId) - ->willReturn(true); - $this->assertTrue($this->notificationTime->unsetLastTimeNotificationValueForCurrentUser()); - } -} diff --git a/app/code/Magento/Analytics/etc/module.xml b/app/code/Magento/Analytics/etc/module.xml index 37d1a9e79ad70..32ee5d23a4d86 100644 --- a/app/code/Magento/Analytics/etc/module.xml +++ b/app/code/Magento/Analytics/etc/module.xml @@ -12,7 +12,6 @@ - diff --git a/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml b/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml index 3bfb5ca595790..a8f62d6d891a9 100644 --- a/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml +++ b/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml @@ -9,7 +9,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> - + - - diff --git a/app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/analytics-icon.svg b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/analytics-icon.svg new file mode 100644 index 0000000000000..fde91d775d444 --- /dev/null +++ b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/analytics-icon.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php b/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php deleted file mode 100644 index 0ea32df272729..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php +++ /dev/null @@ -1,56 +0,0 @@ -configuration = $configuration; - } - - /** - * Cancel subscription for functional tests - * - * @param AbstractState $state - * @return bool - * @throws \Exception - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function execute(AbstractState $state) - { - $url = $_ENV['app_backend_url'] . 'analytics/subscription/postpone'; - $curl = new BackendDecorator(new CurlTransport(), $this->configuration); - $curl->write($url, []); - $response = $curl->read(); - $curl->close(); - if (isset($response['success'])) { - return $response['success']; - } - return false; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml index 74b10cca43c1f..946be3f01537a 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml @@ -6,13 +6,6 @@ */ --> - - - - Magento\Analytics\Mtf\App\State\NotificationTimeHandler - - - S1 @@ -33,19 +26,4 @@ S1 - - - S1 - - - - - S1 - - - - - S1 - - diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php index 395fa4cd4d81f..53c36e0a1e1b0 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php @@ -30,11 +30,6 @@ class UpgradeSystemTest extends Injectable */ protected $adminDashboard; - /** - * @var \Magento\Analytics\Mtf\App\State\NotificationTimeHandler - */ - private $analyticsNotificationHandler; - /** * @var \Magento\Mtf\Util\Iterator\ApplicationState */ @@ -43,18 +38,15 @@ class UpgradeSystemTest extends Injectable /** * @param Dashboard $adminDashboard * @param SetupWizard $setupWizard - * @param \Magento\Analytics\Mtf\App\State\NotificationTimeHandler $analyticsNotificationHandler * @param \Magento\Mtf\Util\Iterator\ApplicationState $applicationStateIterator */ public function __inject( Dashboard $adminDashboard, SetupWizard $setupWizard, - \Magento\Analytics\Mtf\App\State\NotificationTimeHandler $analyticsNotificationHandler, \Magento\Mtf\Util\Iterator\ApplicationState $applicationStateIterator ) { $this->adminDashboard = $adminDashboard; $this->setupWizard = $setupWizard; - $this->analyticsNotificationHandler = $analyticsNotificationHandler; $this->applicationStateIterator = $applicationStateIterator; } @@ -141,11 +133,6 @@ public function test( $assertSuccessMessage->processAssert($this->setupWizard, $upgrade['package']); - // Disable promotion popup for Analytics module - $appStateMetadata = $this->applicationStateIterator->current(); - $appState = \Magento\Mtf\ObjectManager::getInstance()->get($appStateMetadata['class']); - $this->analyticsNotificationHandler->execute($appState); - // Check application version $this->adminDashboard->open(); $assertApplicationVersion->processAssert($this->adminDashboard, $version); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js deleted file mode 100644 index 9f691c8dc2d05..0000000000000 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -/* global jQuery */ -/* eslint-disable max-nested-callbacks */ -define([ - 'jquery', - 'squire' -], function ($, Squire) { - 'use strict'; - - var injector = new Squire(), - mocks = { - 'Magento_Ui/js/modal/alert': jasmine.createSpy(), - 'uiRegistry': jasmine.createSpy() - }, - obj; - - describe('Magento_Analytics/js/modal/modal-component', function () { - beforeEach(function (done) { - injector.mock(mocks); - injector.require(['Magento_Analytics/js/modal/modal-component'], function (Constr) { - obj = new Constr({ - provider: 'provName', - name: '', - index: '', - links: '', - listens: '', - - /** - * @return {Object} source - mock for form data - */ - form: function () { - return { - source: { - data: {} - } - }; - } - }); - done(); - }); - }); - describe('"sendPostponeRequest" method', function () { - it('should send a ajax request', function () { - jQuery.ajax = jasmine.createSpy().and.callFake(function () { - var d = $.Deferred(); - - d.resolve({ - 'success': true - }); - - return d.promise(); - }); - - obj.sendPostponeRequest({}); - - expect(jQuery.ajax).toHaveBeenCalled(); - }); - - it('should call "onError" method if ajax received error', function () { - spyOn(obj, 'onError'); - jQuery.ajax = jasmine.createSpy().and.callFake(function () { - var d = $.Deferred(); - - d.resolve({ - 'error': true - }); - - return d.promise(); - }); - - obj.sendPostponeRequest({}); - - expect(jQuery.ajax).toHaveBeenCalled(); - expect(obj.onError).toHaveBeenCalled(); - }); - - it('should call "onError" method if request failed', function () { - spyOn(obj, 'onError'); - jQuery.ajax = jasmine.createSpy().and.callFake(function () { - var d = $.Deferred(); - - d.reject(); - - return d.promise(); - }); - - obj.sendPostponeRequest({}); - - expect(jQuery.ajax).toHaveBeenCalled(); - expect(obj.onError).toHaveBeenCalled(); - }); - }); - - describe('"onError" method', function () { - var abortRequest = { - statusText: 'abort' - }, - errorRequest = { - error: true, - message: 'Error text' - }; - - it('should do nothing if request aborted', function () { - expect(obj.onError(abortRequest)).toBeUndefined(); - }); - - it('should show alert with error', function () { - obj.onError(errorRequest); - expect(mocks['Magento_Ui/js/modal/alert']).toHaveBeenCalled(); - }); - }); - - describe('"actionCancel" method', function () { - it('should call "sendPostponeRequest" and "closeModal" methods', function () { - spyOn(obj, 'sendPostponeRequest'); - spyOn(obj, 'closeModal'); - obj.actionCancel(); - expect(obj.sendPostponeRequest).toHaveBeenCalledWith(obj.postponeOptions); - expect(obj.closeModal).toHaveBeenCalled(); - }); - }); - }); -}); From 97b336d375227fe8a184337cc0341283770affeb Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Thu, 5 Oct 2017 15:18:39 -0500 Subject: [PATCH 020/194] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- .../functional/tests/app/Magento/Analytics/Test/etc/di.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml index cc113f1768e2e..ac51a3e2b6dd8 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml @@ -6,13 +6,6 @@ */ --> - - - - Magento\Analytics\Mtf\App\State\NotificationTimeHandler - - - S1 From eefdc1cdb6c21298e135fbbf986cabf742647caa Mon Sep 17 00:00:00 2001 From: Romain Ruaud Date: Thu, 5 Oct 2017 16:15:21 +0200 Subject: [PATCH 021/194] Fixing keyboard submit of adminhtml suggest form. --- lib/web/mage/backend/suggest.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/web/mage/backend/suggest.js b/lib/web/mage/backend/suggest.js index 81bde35f9e12a..2ce3405783ea1 100644 --- a/lib/web/mage/backend/suggest.js +++ b/lib/web/mage/backend/suggest.js @@ -245,6 +245,20 @@ case keyCode.ENTER: case keyCode.NUMPAD_ENTER: + suggestList = event.currentTarget.parentNode.getElementsByTagName('ul')[0]; + hasSelectedItems = suggestList.getElementsByClassName('_active').length >= 0; + + if (hasSelectedItems) { + selectedItem = $(suggestList.getElementsByClassName('_active')[0]); + /* eslint-disable max-depth */ + if (selectedItem.find('a') && selectedItem.find('a').attr('href') !== undefined) { + window.location = selectedItem.find('a').attr('href'); + event.preventDefault(); + + return false; + } + /* eslint-enable max-depth */ + } if (this.isDropdownShown() && this._focused) { this._proxyEvents(event); From cad0c4528b91ee1c20f473235b054e5506e8d719 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Fri, 6 Oct 2017 11:49:03 -0500 Subject: [PATCH 022/194] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- .../Model/Condition/CanViewNotification.php | 28 +++-- .../Analytics/Model/NotificationFlag.php | 75 ------------ .../Model/NotificationFlagManager.php | 56 +++++++++ .../Condition/CanViewNotificationTest.php | 49 +++++--- .../Model/NotificationFlagManagerTest.php | 67 +++++++++++ .../Test/Unit/Model/NotificationFlagTest.php | 107 ------------------ 6 files changed, 178 insertions(+), 204 deletions(-) delete mode 100644 app/code/Magento/Analytics/Model/NotificationFlag.php create mode 100644 app/code/Magento/Analytics/Model/NotificationFlagManager.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php delete mode 100644 app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php index e66b9fa2d722d..9f1e48fb2c8f7 100644 --- a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -5,8 +5,9 @@ */ namespace Magento\Analytics\Model\Condition; +use Magento\Backend\Model\Auth\Session; use Magento\Framework\View\Layout\Condition\VisibilityConditionInterface; -use Magento\Analytics\Model\NotificationFlag; +use Magento\Analytics\Model\NotificationFlagManager; /** * Class CanViewNotification @@ -22,33 +23,42 @@ class CanViewNotification implements VisibilityConditionInterface const NAME = 'can_view_notification'; /** - * @var NotificationFlag + * @var NotificationFlagManager */ - private $notificationFlag; + private $notificationFlagManager; + + /** + * @var Session + */ + private $session; /** * CanViewNotification constructor. * - * @param NotificationFlag $notificationFlag + * @param NotificationFlagManager $notificationFlagManager + * @param Session $session */ public function __construct( - NotificationFlag $notificationFlag + NotificationFlagManager $notificationFlagManager, + Session $session ) { - $this->notificationFlag = $notificationFlag; + $this->notificationFlagManager = $notificationFlagManager; + $this->session = $session; } /** - * Validate if notification popup can be shown + * Validate if notification popup can be shown and set the notification flag * * @inheritdoc */ public function isVisible(array $arguments) { - if ($this->notificationFlag->hasNotificationValueForCurrentUser()) { + $userId = $this->session->getUser()->getId(); + if ($this->notificationFlagManager->isUserNotified($userId)) { return false; } - return $this->notificationFlag->storeNotificationValueForCurrentUser(); + return $this->notificationFlagManager->setNotifiedUser($userId); } /** diff --git a/app/code/Magento/Analytics/Model/NotificationFlag.php b/app/code/Magento/Analytics/Model/NotificationFlag.php deleted file mode 100644 index 7f282934d6d28..0000000000000 --- a/app/code/Magento/Analytics/Model/NotificationFlag.php +++ /dev/null @@ -1,75 +0,0 @@ -flagManager = $flagManager; - $this->session = $session; - } - - /** - * Stores flag to indicate the user was notified about Analytic services - * - * @return bool - */ - public function storeNotificationValueForCurrentUser() - { - $flagCode = self::NOTIFICATION_SEEN . $this->session->getUser()->getId(); - return $this->flagManager->saveFlag($flagCode, 1); - } - - /** - * Returns the flag data if the user was notified about Analytic services - * - * @return bool - */ - public function hasNotificationValueForCurrentUser() - { - return $this->flagManager->getFlagData(self::NOTIFICATION_SEEN . $this->session->getUser()->getId()); - } - - /** - * Remove the notification seen flag - * - * @return bool - */ - public function unsetNotificationValueForCurrentUser() - { - return $this->flagManager->deleteFlag(self::NOTIFICATION_SEEN . $this->session->getUser()->getId()); - } -} diff --git a/app/code/Magento/Analytics/Model/NotificationFlagManager.php b/app/code/Magento/Analytics/Model/NotificationFlagManager.php new file mode 100644 index 0000000000000..624e0ab6bcdd1 --- /dev/null +++ b/app/code/Magento/Analytics/Model/NotificationFlagManager.php @@ -0,0 +1,56 @@ +flagManager = $flagManager; + } + + /** + * Sets the flag to indicate the user was notified about Analytic services + * @param $userId + * @return bool + */ + public function setNotifiedUser($userId) + { + $flagCode = self::NOTIFICATION_SEEN . $userId; + return $this->flagManager->saveFlag($flagCode, 1); + } + + /** + * Returns the flag data if the user was notified about Analytic services + * @param $userId + * @return bool + */ + public function isUserNotified($userId) + { + return $this->flagManager->getFlagData(self::NOTIFICATION_SEEN . $userId); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index e7eafcdbe7024..d8882f1fe1887 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -8,7 +8,8 @@ use Magento\Analytics\Model\Condition\CanViewNotification; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Analytics\Model\NotificationFlag; +use Magento\Analytics\Model\notificationFlagManager; +use Magento\Backend\Model\Auth\Session; /** * Class CanViewNotificationTest @@ -16,44 +17,66 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase { /** - * @var NotificationFlag|\PHPUnit_Framework_MockObject_MockObject + * @var CanViewNotification */ - private $notificationFlagMock; + private $canViewNotification; /** - * @var CanViewNotification + * @var NotificationFlagManager|\PHPUnit_Framework_MockObject_MockObject */ - private $canViewNotification; + private $notificationFlagManagerMock; + + /** + * @var Session|\PHPUnit_Framework_MockObject_MockObject + */ + private $sessionMock; public function setUp() { - $this->notificationFlagMock = $this->getMockBuilder(NotificationFlag::class) + $this->notificationFlagManagerMock = $this->getMockBuilder(NotificationFlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->sessionMock = $this->getMockBuilder(Session::class) ->disableOriginalConstructor() + ->setMethods(['getUser', 'getId']) ->getMock(); $objectManager = new ObjectManager($this); $this->canViewNotification = $objectManager->getObject( CanViewNotification::class, [ - 'notificationFlag' => $this->notificationFlagMock + 'notificationFlagManager' => $this->notificationFlagManagerMock, + 'session' => $this->sessionMock ] ); } public function testUserShouldSeeNotification() { - $this->notificationFlagMock->expects($this->once()) - ->method('hasNotificationValueForCurrentUser') + $this->sessionMock->expects($this->once()) + ->method('getUser') + ->willReturnSelf(); + $this->sessionMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + $this->notificationFlagManagerMock->expects($this->once()) + ->method('isUserNotified') ->willReturn(false); - $this->notificationFlagMock->expects($this->once()) - ->method('storeNotificationValueForCurrentUser') + $this->notificationFlagManagerMock->expects($this->once()) + ->method('setNotifiedUser') ->willReturn(true); $this->assertTrue($this->canViewNotification->isVisible([])); } public function testUserShouldNotSeeNotification() { - $this->notificationFlagMock->expects($this->once()) - ->method('hasNotificationValueForCurrentUser') + $this->sessionMock->expects($this->once()) + ->method('getUser') + ->willReturnSelf(); + $this->sessionMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + $this->notificationFlagManagerMock->expects($this->once()) + ->method('isUserNotified') ->willReturn(true); $this->assertFalse($this->canViewNotification->isVisible([])); } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php new file mode 100644 index 0000000000000..8438f86449153 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php @@ -0,0 +1,67 @@ +userId = 1; + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManagerHelper = new ObjectManagerHelper($this); + $this->notificationFlagManager = $objectManagerHelper->getObject( + NotificationFlagManager::class, + [ + 'flagManager' => $this->flagManagerMock + ] + ); + } + + public function testSetNotifiedUser() + { + $this->flagManagerMock + ->expects($this->once()) + ->method('saveFlag') + ->with(NotificationFlagManager::NOTIFICATION_SEEN . $this->userId, 1) + ->willReturn(true); + $this->assertTrue($this->notificationFlagManager->setNotifiedUser($this->userId)); + } + + public function testIsUserNotified() + { + $this->flagManagerMock + ->expects($this->once()) + ->method('getFlagData') + ->with(NotificationFlagManager::NOTIFICATION_SEEN . $this->userId) + ->willReturn(true); + $this->assertTrue($this->notificationFlagManager->isUserNotified($this->userId)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php deleted file mode 100644 index 94816cb0965c5..0000000000000 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php +++ /dev/null @@ -1,107 +0,0 @@ -userId = 1; - - $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) - ->disableOriginalConstructor() - ->getMock(); - $this->sessionMock = $this->getMockBuilder(Session::class) - ->disableOriginalConstructor() - ->setMethods(['getUser', 'getId']) - ->getMock(); - $objectManagerHelper = new ObjectManagerHelper($this); - $this->notificationFlag = $objectManagerHelper->getObject( - NotificationFlag::class, - [ - 'flagManager' => $this->flagManagerMock, - 'session' => $this->sessionMock - ] - ); - } - - public function testStoreNotificationValueForCurrentUser() - { - $this->sessionMock->expects($this->once()) - ->method('getUser') - ->willReturnSelf(); - $this->sessionMock->expects($this->once()) - ->method('getId') - ->willReturn(1); - $this->flagManagerMock - ->expects($this->once()) - ->method('saveFlag') - ->with(NotificationFlag::NOTIFICATION_SEEN . $this->userId, 1) - ->willReturn(true); - $this->assertTrue($this->notificationFlag->storeNotificationValueForCurrentUser()); - } - - public function testHasNotificationValueForCurrentUser() - { - $this->sessionMock->expects($this->once()) - ->method('getUser') - ->willReturnSelf(); - $this->sessionMock->expects($this->once()) - ->method('getId') - ->willReturn(1); - $this->flagManagerMock - ->expects($this->once()) - ->method('getFlagData') - ->with(NotificationFlag::NOTIFICATION_SEEN . $this->userId) - ->willReturn(true); - $this->assertTrue($this->notificationFlag->hasNotificationValueForCurrentUser()); - } - - public function testUnsetNotificationValueForCurrentUser() - { - $this->sessionMock->expects($this->once()) - ->method('getUser') - ->willReturnSelf(); - $this->sessionMock->expects($this->once()) - ->method('getId') - ->willReturn(1); - $this->flagManagerMock - ->expects($this->once()) - ->method('deleteFlag') - ->with(NotificationFlag::NOTIFICATION_SEEN . $this->userId) - ->willReturn(true); - $this->assertTrue($this->notificationFlag->unsetNotificationValueForCurrentUser()); - } -} From aabdf799f950072e141f77893059933e22f921d9 Mon Sep 17 00:00:00 2001 From: Joan He Date: Sat, 7 Oct 2017 07:54:34 -0500 Subject: [PATCH 023/194] Merge remote-tracking branch 'upstream/2.2-develop' into MAGETWO-71458-analytics # Conflicts: # composer.lock --- composer.lock | 94 +++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/composer.lock b/composer.lock index 5673d2620a94b..2d43d7ff9163a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "e9655626aff3d3314ffaab8bd609154c", - "content-hash": "bcd940e542a85144ed6e61f7ca9334d6", + "hash": "24aca194b219901b445f7acc8f3a1c16", + "content-hash": "a3dbf15e8a5ad7687ca8b391486311a0", "packages": [ { "name": "braintree/braintree_php", @@ -494,16 +494,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "5.2.2", + "version": "5.2.4", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "b80053b620826810b38211b3c5f935ba9cddf6b3" + "reference": "7ccb0e67ea8ace0f84c40900ca3c8a234467628c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/b80053b620826810b38211b3c5f935ba9cddf6b3", - "reference": "b80053b620826810b38211b3c5f935ba9cddf6b3", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/7ccb0e67ea8ace0f84c40900ca3c8a234467628c", + "reference": "7ccb0e67ea8ace0f84c40900ca3c8a234467628c", "shasum": "" }, "require": { @@ -556,7 +556,7 @@ "json", "schema" ], - "time": "2017-10-03 00:49:49" + "time": "2017-10-04 20:57:36" }, { "name": "league/climate", @@ -1479,16 +1479,16 @@ }, { "name": "symfony/console", - "version": "v2.8.27", + "version": "v2.8.28", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c0807a2ca978e64d8945d373a9221a5c35d1a253" + "reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c0807a2ca978e64d8945d373a9221a5c35d1a253", - "reference": "c0807a2ca978e64d8945d373a9221a5c35d1a253", + "url": "https://api.github.com/repos/symfony/console/zipball/f81549d2c5fdee8d711c9ab3c7e7362353ea5853", + "reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853", "shasum": "" }, "require": { @@ -1536,7 +1536,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-08-27 14:29:03" + "time": "2017-10-01 21:00:16" }, { "name": "symfony/debug", @@ -1597,16 +1597,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v2.8.27", + "version": "v2.8.28", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "1377400fd641d7d1935981546aaef780ecd5bf6d" + "reference": "7fe089232554357efb8d4af65ce209fc6e5a2186" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1377400fd641d7d1935981546aaef780ecd5bf6d", - "reference": "1377400fd641d7d1935981546aaef780ecd5bf6d", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7fe089232554357efb8d4af65ce209fc6e5a2186", + "reference": "7fe089232554357efb8d4af65ce209fc6e5a2186", "shasum": "" }, "require": { @@ -1653,20 +1653,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2017-06-02 07:47:27" + "time": "2017-10-01 21:00:16" }, { "name": "symfony/filesystem", - "version": "v3.3.9", + "version": "v3.3.10", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "b32a0e5f928d0fa3d1dd03c78d020777e50c10cb" + "reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/b32a0e5f928d0fa3d1dd03c78d020777e50c10cb", - "reference": "b32a0e5f928d0fa3d1dd03c78d020777e50c10cb", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/90bc45abf02ae6b7deb43895c1052cb0038506f1", + "reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1", "shasum": "" }, "require": { @@ -1702,20 +1702,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2017-07-29 21:54:42" + "time": "2017-10-03 13:33:10" }, { "name": "symfony/finder", - "version": "v3.3.9", + "version": "v3.3.10", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "b2260dbc80f3c4198f903215f91a1ac7fe9fe09e" + "reference": "773e19a491d97926f236942484cb541560ce862d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/b2260dbc80f3c4198f903215f91a1ac7fe9fe09e", - "reference": "b2260dbc80f3c4198f903215f91a1ac7fe9fe09e", + "url": "https://api.github.com/repos/symfony/finder/zipball/773e19a491d97926f236942484cb541560ce862d", + "reference": "773e19a491d97926f236942484cb541560ce862d", "shasum": "" }, "require": { @@ -1751,7 +1751,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2017-07-29 21:54:42" + "time": "2017-10-02 06:42:24" }, { "name": "symfony/polyfill-mbstring", @@ -1814,16 +1814,16 @@ }, { "name": "symfony/process", - "version": "v2.8.27", + "version": "v2.8.28", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "57e52a0a6a80ea0aec4fc1b785a7920a95cb88a8" + "reference": "26c9fb02bf06bd6b90f661a5bd17e510810d0176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/57e52a0a6a80ea0aec4fc1b785a7920a95cb88a8", - "reference": "57e52a0a6a80ea0aec4fc1b785a7920a95cb88a8", + "url": "https://api.github.com/repos/symfony/process/zipball/26c9fb02bf06bd6b90f661a5bd17e510810d0176", + "reference": "26c9fb02bf06bd6b90f661a5bd17e510810d0176", "shasum": "" }, "require": { @@ -1859,7 +1859,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-07-03 08:04:30" + "time": "2017-10-01 21:00:16" }, { "name": "tedivm/jshrink", @@ -5528,16 +5528,16 @@ }, { "name": "symfony/config", - "version": "v3.3.9", + "version": "v3.3.10", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "f9f19a39ee178f61bb2190f51ff7c517c2159315" + "reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/f9f19a39ee178f61bb2190f51ff7c517c2159315", - "reference": "f9f19a39ee178f61bb2190f51ff7c517c2159315", + "url": "https://api.github.com/repos/symfony/config/zipball/4ab62407bff9cd97c410a7feaef04c375aaa5cfd", + "reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd", "shasum": "" }, "require": { @@ -5586,20 +5586,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2017-09-04 16:28:07" + "time": "2017-10-04 18:56:58" }, { "name": "symfony/dependency-injection", - "version": "v3.3.9", + "version": "v3.3.10", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "e593f06dd90a81c7b70ac1c49862a061b0ec06d2" + "reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e593f06dd90a81c7b70ac1c49862a061b0ec06d2", - "reference": "e593f06dd90a81c7b70ac1c49862a061b0ec06d2", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8ebad929aee3ca185b05f55d9cc5521670821ad1", + "reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1", "shasum": "" }, "require": { @@ -5656,7 +5656,7 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2017-09-05 20:39:38" + "time": "2017-10-04 17:15:30" }, { "name": "symfony/polyfill-php54", @@ -5936,16 +5936,16 @@ }, { "name": "symfony/stopwatch", - "version": "v3.3.9", + "version": "v3.3.10", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "9a5610a8d6a50985a7be485c0ba745c22607beeb" + "reference": "170edf8b3247d7b6779eb6fa7428f342702ca184" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/9a5610a8d6a50985a7be485c0ba745c22607beeb", - "reference": "9a5610a8d6a50985a7be485c0ba745c22607beeb", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/170edf8b3247d7b6779eb6fa7428f342702ca184", + "reference": "170edf8b3247d7b6779eb6fa7428f342702ca184", "shasum": "" }, "require": { @@ -5981,7 +5981,7 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2017-07-29 21:54:42" + "time": "2017-10-02 06:42:24" }, { "name": "theseer/fdomdocument", From 53f999eaec107586d3a7bdd1c02f0ede8c7ed753 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Mon, 9 Oct 2017 15:16:52 -0500 Subject: [PATCH 024/194] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- .../Model/NotificationFlagManager.php | 6 +++- .../Condition/CanViewNotificationTest.php | 35 ++++++++++--------- .../Model/NotificationFlagManagerTest.php | 18 ++++------ 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/app/code/Magento/Analytics/Model/NotificationFlagManager.php b/app/code/Magento/Analytics/Model/NotificationFlagManager.php index 624e0ab6bcdd1..6fdc88352ed00 100644 --- a/app/code/Magento/Analytics/Model/NotificationFlagManager.php +++ b/app/code/Magento/Analytics/Model/NotificationFlagManager.php @@ -51,6 +51,10 @@ public function setNotifiedUser($userId) */ public function isUserNotified($userId) { - return $this->flagManager->getFlagData(self::NOTIFICATION_SEEN . $userId); + if ($this->flagManager->getFlagData(self::NOTIFICATION_SEEN . $userId)) { + return true; + } + + return false; } } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index d8882f1fe1887..45a30ea1113a7 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -50,34 +50,35 @@ public function setUp() ); } - public function testUserShouldSeeNotification() + public function isVisibleProvider() { - $this->sessionMock->expects($this->once()) - ->method('getUser') - ->willReturnSelf(); - $this->sessionMock->expects($this->once()) - ->method('getId') - ->willReturn(1); - $this->notificationFlagManagerMock->expects($this->once()) - ->method('isUserNotified') - ->willReturn(false); - $this->notificationFlagManagerMock->expects($this->once()) - ->method('setNotifiedUser') - ->willReturn(true); - $this->assertTrue($this->canViewNotification->isVisible([])); + return [ + [1, false, true], + [1, true, false] + ]; } - public function testUserShouldNotSeeNotification() + /** + * @dataProvider isVisibleProvider + * @param int $userId + * @param bool $isUserNotified + * @param bool $expected + */ + public function testIsVisible($userId, $isUserNotified, $expected) { $this->sessionMock->expects($this->once()) ->method('getUser') ->willReturnSelf(); $this->sessionMock->expects($this->once()) ->method('getId') - ->willReturn(1); + ->willReturn($userId); $this->notificationFlagManagerMock->expects($this->once()) ->method('isUserNotified') + ->willReturn($isUserNotified); + $this->notificationFlagManagerMock->expects($this->any()) + ->method('setNotifiedUser') ->willReturn(true); - $this->assertFalse($this->canViewNotification->isVisible([])); + + $this->assertEquals($expected, $this->canViewNotification->isVisible([])); } } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php index 8438f86449153..3061ec98e6b1a 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php @@ -11,7 +11,7 @@ use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; /** - * Class NotificationFlagTest + * Class NotificationFlagManagerTest */ class NotificationFlagManagerTest extends \PHPUnit\Framework\TestCase { @@ -25,14 +25,8 @@ class NotificationFlagManagerTest extends \PHPUnit\Framework\TestCase */ private $notificationFlagManager; - /** - * @var int - */ - private $userId; - public function setUp() { - $this->userId = 1; $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) ->disableOriginalConstructor() ->getMock(); @@ -47,21 +41,23 @@ public function setUp() public function testSetNotifiedUser() { + $userId = 1; $this->flagManagerMock ->expects($this->once()) ->method('saveFlag') - ->with(NotificationFlagManager::NOTIFICATION_SEEN . $this->userId, 1) + ->with(NotificationFlagManager::NOTIFICATION_SEEN . $userId, 1) ->willReturn(true); - $this->assertTrue($this->notificationFlagManager->setNotifiedUser($this->userId)); + $this->assertTrue($this->notificationFlagManager->setNotifiedUser($userId)); } public function testIsUserNotified() { + $userId = 1; $this->flagManagerMock ->expects($this->once()) ->method('getFlagData') - ->with(NotificationFlagManager::NOTIFICATION_SEEN . $this->userId) + ->with(NotificationFlagManager::NOTIFICATION_SEEN . $userId) ->willReturn(true); - $this->assertTrue($this->notificationFlagManager->isUserNotified($this->userId)); + $this->assertTrue($this->notificationFlagManager->isUserNotified($userId)); } } From ce4fb9740ec8a362f77110ff9755f871d5187fdd Mon Sep 17 00:00:00 2001 From: Thiago Lima Date: Tue, 10 Oct 2017 13:43:37 +0200 Subject: [PATCH 025/194] #11211 Fix Store View switcher --- app/code/Magento/Store/Model/Store.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index 1d100da274465..f9db40c05a332 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -1166,6 +1166,9 @@ public function getCurrentUrl($fromStore = true) if (!$this->isUseStoreInUrl()) { $storeParsedQuery['___store'] = $this->getCode(); } + if ($this->getCode() !== $this->_storeManager->getStore()->getCode()) { + $fromStore = true; + } if ($fromStore !== false) { $storeParsedQuery['___from_store'] = $fromStore === true ? $this->_storeManager->getStore()->getCode() : $fromStore; @@ -1175,9 +1178,14 @@ public function getCurrentUrl($fromStore = true) . '://' . $storeParsedUrl['host'] . (isset($storeParsedUrl['port']) ? ':' . $storeParsedUrl['port'] : '') - . $storeParsedUrl['path'] - . $requestString - . ($storeParsedQuery ? '?' . http_build_query($storeParsedQuery, '', '&') : ''); + . $storeParsedUrl['path']; + + //avoid query params duplication + if (!preg_match('/___store=(.*?)&___from_store=(.*?)/', $requestString)) { + $currentUrl .= $requestString; + } + + $currentUrl .= ($storeParsedQuery ? '?' . http_build_query($storeParsedQuery, '', '&') : ''); return $currentUrl; } From ad8cb5ccd8ab29fddfae1448593efb47c044fe75 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 11:45:43 -0500 Subject: [PATCH 026/194] MAGETWO-80479: Update existing Advanced Reporting tests - Update naming --- .../AssertConfigAnalyticsDisabled.php | 11 +++++------ .../Constraint/AssertConfigAnalyticsEnabled.php | 11 +++++------ ...p => AssertConfigAnalyticsIndustryScope.php} | 10 +++++----- ...php => AssertEmptyIndustryCanNotBeSaved.php} | 10 +++++----- ...erticalIsSet.php => AssertIndustryIsSet.php} | 16 ++++++++-------- .../Analytics/Test/TestCase/InstallTest.xml | 17 +++++++++++++++++ ...{SetVerticalTest.php => SetIndustryTest.php} | 2 +- ...{SetVerticalTest.xml => SetIndustryTest.xml} | 6 +++--- 8 files changed, 49 insertions(+), 34 deletions(-) rename dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/{AssertConfigAnalyticsVerticalScope.php => AssertConfigAnalyticsIndustryScope.php} (64%) rename dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/{AssertEmptyVerticalCanNotBeSaved.php => AssertEmptyIndustryCanNotBeSaved.php} (64%) rename dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/{AssertVerticalIsSet.php => AssertIndustryIsSet.php} (62%) create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml rename dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/{SetVerticalTest.php => SetIndustryTest.php} (95%) rename dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/{SetVerticalTest.xml => SetIndustryTest.xml} (89%) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php index daeed6a66cfa4..0f65835a32aa7 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php @@ -10,12 +10,12 @@ use Magento\Mtf\Constraint\AbstractConstraint; /** - * Assert Analytics is disabled in Stores>Configuration>General>Analytics->General menu. + * Assert Advanced Reporting service is disabled */ class AssertConfigAnalyticsDisabled extends AbstractConstraint { /** - * Assert Analytics is disabled in Stores > Configuration > General > Analytics menu. + * Assert Advanced Reporting service is disabled. * * @param ConfigAnalytics $configAnalytics * @param OpenAnalyticsConfigStep $openAnalyticsConfigStep @@ -27,12 +27,12 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon \PHPUnit_Framework_Assert::assertFalse( (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), - 'Magento Analytics is not disabled.' + 'Magento Advanced Reporting service is not disabled.' ); \PHPUnit_Framework_Assert::assertEquals( $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), 'Subscription status: Disabled', - 'Magento Analytics status is not disabled.' + 'Magento Advanced Reporting service subscription status is not disabled.' ); } @@ -43,7 +43,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon */ public function toString() { - return 'Magento Analytics is disabled in Stores > Configuration > General > Analytics > General menu' - . ' and has Disabled status.'; + return 'Magento Advanced Reporting service is disabled and has Disabled status.'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php index eb699105e1906..8fd04e06b14bb 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php @@ -10,12 +10,12 @@ use Magento\Mtf\Constraint\AbstractConstraint; /** - * Assert Analytics is enabled in Stores > Configuration > General > Analytics > General menu. + * Assert Advanced Reporting Service is enabled. */ class AssertConfigAnalyticsEnabled extends AbstractConstraint { /** - * Assert Analytics is enabled in Stores > Configuration > General > Analytics menu. + * Assert Advanced Reporting service is enabled. * * @param ConfigAnalytics $configAnalytics * @param OpenAnalyticsConfigStep $openAnalyticsConfigStep @@ -27,13 +27,13 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon \PHPUnit_Framework_Assert::assertTrue( (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), - 'Magento Analytics is not enabled.' + 'Magento Advanced Reporting service is not enabled.' ); \PHPUnit_Framework_Assert::assertEquals( $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), 'Subscription status: Pending', - 'Magento Analytics status is not pending.' + 'Magento Advanced Reporting service subscription status is not pending.' ); } @@ -44,7 +44,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon */ public function toString() { - return 'Magento Analytics is enabled and has Pending status in' - . ' Stores > Configuration > General > Analytics > General menu.'; + return 'Magento Advanced Reporting service is enabled and has Pending status'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsIndustryScope.php similarity index 64% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsIndustryScope.php index 3793292653cbf..bb208dbb379c8 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsIndustryScope.php @@ -9,12 +9,12 @@ use Magento\Analytics\Test\Page\Adminhtml\ConfigAnalytics; /** - * Assert Analytics vertical scope is website in Stores > Configuration > General > Analytics > General menu. + * Assert Advanced Reporting industry scope is website in Stores. */ -class AssertConfigAnalyticsVerticalScope extends AbstractConstraint +class AssertConfigAnalyticsIndustryScope extends AbstractConstraint { /** - * Assert Analytics vertical scope is website in Stores > Configuration > General > Analytics menu. + * Assert Advanced Reporting industry scope is website in Stores. * * @param ConfigAnalytics $configAnalytics */ @@ -23,7 +23,7 @@ public function processAssert(ConfigAnalytics $configAnalytics) \PHPUnit_Framework_Assert::assertEquals( true, $configAnalytics->getAnalyticsForm()->getAnalyticsVerticalScope(), - 'Magento Analytics vertical scope is not website' + 'Magento Advanced Reporting industry scope is not website' ); } @@ -34,6 +34,6 @@ public function processAssert(ConfigAnalytics $configAnalytics) */ public function toString() { - return 'Magento Analytics vertical scope is website'; + return 'Magento Advanced Reporting industry scope is website'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyIndustryCanNotBeSaved.php similarity index 64% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyIndustryCanNotBeSaved.php index 3cf503047e6ea..5e86c13b8bbae 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyIndustryCanNotBeSaved.php @@ -9,12 +9,12 @@ use Magento\Analytics\Test\Page\Adminhtml\ConfigAnalytics; /** - * Assert Analytics empty Vertical can not be saved in Stores > Configuration > General > Analytics > General menu. + * Assert empty industry can not be saved in advanced reporting configuration. */ -class AssertEmptyVerticalCanNotBeSaved extends AbstractConstraint +class AssertEmptyIndustryCanNotBeSaved extends AbstractConstraint { /** - * Assert Analytics empty Vertical can not be saved in Stores > Configuration > General > Analytics > General menu. + * Assert empty industry can not be saved in Advanced Reporting configuration. * * @param ConfigAnalytics $configAnalytics * @param string $errorMessage @@ -25,7 +25,7 @@ public function processAssert(ConfigAnalytics $configAnalytics, $errorMessage) \PHPUnit_Framework_Assert::assertEquals( $errorMessage, $configAnalytics->getMessages()->getErrorMessage(), - 'There is no error message when saving empty vertical in configuration' + 'There is no error message when saving empty industry in configuration' ); } @@ -37,6 +37,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, $errorMessage) public function toString() { return - 'Empty Magento Analytics vertical can not be saved'; + 'Empty Magento Advanced Reporting industry can not be saved'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertIndustryIsSet.php similarity index 62% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertIndustryIsSet.php index 514c83a30ff51..635c4b35324ed 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertIndustryIsSet.php @@ -9,23 +9,23 @@ use Magento\Analytics\Test\Page\Adminhtml\ConfigAnalytics; /** - * Assert Analytics Vertical is set in Stores > Configuration > General > Analytics > General menu. + * Assert Advance Reporting Industry is set. */ -class AssertVerticalIsSet extends AbstractConstraint +class AssertIndustryIsSet extends AbstractConstraint { /** - * Assert Analytics Vertical is set in Stores > Configuration > General > Analytics > General menu. + * Assert Advance Reporting Industry is set * * @param ConfigAnalytics $configAnalytics - * @param string $vertical + * @param string $industry * @return void */ - public function processAssert(ConfigAnalytics $configAnalytics, $vertical) + public function processAssert(ConfigAnalytics $configAnalytics, $industry) { \PHPUnit_Framework_Assert::assertEquals( - $vertical, + $industry, $configAnalytics->getAnalyticsForm()->getAnalyticsVertical(), - $vertical . 'vertical is not selected' + $industry . 'industry is not selected' ); } @@ -37,6 +37,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, $vertical) public function toString() { return - 'Proper Magento Analytics vertical is selected'; + 'Proper Magento Advanced Reporting industry is selected'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml new file mode 100644 index 0000000000000..5ce0a2f1556fd --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml @@ -0,0 +1,17 @@ + + + + + + severity:S1 + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php similarity index 95% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php index a721774f4d22c..0ff682c09c662 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php @@ -18,7 +18,7 @@ * * @ZephyrId MAGETWO-63898 */ -class SetVerticalTest extends Injectable +class SetIndustryTest extends Injectable { /* tags */ const MVP = 'no'; diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml similarity index 89% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml rename to dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml index 1db31781ccc2f..dd495fb2afe6b 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml @@ -6,16 +6,16 @@ */ --> - + Apps and Games - + --Please Select-- Please select a vertical. - + From b7f82b6861cbf2596cfb58f837660537f5450918 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 11:57:10 -0500 Subject: [PATCH 027/194] MAGETWO-80479: Update existing Advanced Reporting tests - Update naming --- .../Constraint/AssertConfigAnalyticsDisabled.php | 11 +++++------ .../Constraint/AssertConfigAnalyticsEnabled.php | 11 +++++------ ...hp => AssertConfigAnalyticsIndustryScope.php} | 10 +++++----- ....php => AssertEmptyIndustryCanNotBeSaved.php} | 10 +++++----- ...VerticalIsSet.php => AssertIndustryIsSet.php} | 16 ++++++++-------- .../{SetVerticalTest.php => SetIndustryTest.php} | 2 +- .../{SetVerticalTest.xml => SetIndustryTest.xml} | 8 ++++---- 7 files changed, 33 insertions(+), 35 deletions(-) rename dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/{AssertConfigAnalyticsVerticalScope.php => AssertConfigAnalyticsIndustryScope.php} (64%) rename dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/{AssertEmptyVerticalCanNotBeSaved.php => AssertEmptyIndustryCanNotBeSaved.php} (64%) rename dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/{AssertVerticalIsSet.php => AssertIndustryIsSet.php} (62%) rename dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/{SetVerticalTest.php => SetIndustryTest.php} (95%) rename dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/{SetVerticalTest.xml => SetIndustryTest.xml} (86%) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php index daeed6a66cfa4..0f65835a32aa7 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php @@ -10,12 +10,12 @@ use Magento\Mtf\Constraint\AbstractConstraint; /** - * Assert Analytics is disabled in Stores>Configuration>General>Analytics->General menu. + * Assert Advanced Reporting service is disabled */ class AssertConfigAnalyticsDisabled extends AbstractConstraint { /** - * Assert Analytics is disabled in Stores > Configuration > General > Analytics menu. + * Assert Advanced Reporting service is disabled. * * @param ConfigAnalytics $configAnalytics * @param OpenAnalyticsConfigStep $openAnalyticsConfigStep @@ -27,12 +27,12 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon \PHPUnit_Framework_Assert::assertFalse( (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), - 'Magento Analytics is not disabled.' + 'Magento Advanced Reporting service is not disabled.' ); \PHPUnit_Framework_Assert::assertEquals( $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), 'Subscription status: Disabled', - 'Magento Analytics status is not disabled.' + 'Magento Advanced Reporting service subscription status is not disabled.' ); } @@ -43,7 +43,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon */ public function toString() { - return 'Magento Analytics is disabled in Stores > Configuration > General > Analytics > General menu' - . ' and has Disabled status.'; + return 'Magento Advanced Reporting service is disabled and has Disabled status.'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php index eb699105e1906..8fd04e06b14bb 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php @@ -10,12 +10,12 @@ use Magento\Mtf\Constraint\AbstractConstraint; /** - * Assert Analytics is enabled in Stores > Configuration > General > Analytics > General menu. + * Assert Advanced Reporting Service is enabled. */ class AssertConfigAnalyticsEnabled extends AbstractConstraint { /** - * Assert Analytics is enabled in Stores > Configuration > General > Analytics menu. + * Assert Advanced Reporting service is enabled. * * @param ConfigAnalytics $configAnalytics * @param OpenAnalyticsConfigStep $openAnalyticsConfigStep @@ -27,13 +27,13 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon \PHPUnit_Framework_Assert::assertTrue( (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), - 'Magento Analytics is not enabled.' + 'Magento Advanced Reporting service is not enabled.' ); \PHPUnit_Framework_Assert::assertEquals( $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), 'Subscription status: Pending', - 'Magento Analytics status is not pending.' + 'Magento Advanced Reporting service subscription status is not pending.' ); } @@ -44,7 +44,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon */ public function toString() { - return 'Magento Analytics is enabled and has Pending status in' - . ' Stores > Configuration > General > Analytics > General menu.'; + return 'Magento Advanced Reporting service is enabled and has Pending status'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsIndustryScope.php similarity index 64% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsIndustryScope.php index 3793292653cbf..bb208dbb379c8 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsIndustryScope.php @@ -9,12 +9,12 @@ use Magento\Analytics\Test\Page\Adminhtml\ConfigAnalytics; /** - * Assert Analytics vertical scope is website in Stores > Configuration > General > Analytics > General menu. + * Assert Advanced Reporting industry scope is website in Stores. */ -class AssertConfigAnalyticsVerticalScope extends AbstractConstraint +class AssertConfigAnalyticsIndustryScope extends AbstractConstraint { /** - * Assert Analytics vertical scope is website in Stores > Configuration > General > Analytics menu. + * Assert Advanced Reporting industry scope is website in Stores. * * @param ConfigAnalytics $configAnalytics */ @@ -23,7 +23,7 @@ public function processAssert(ConfigAnalytics $configAnalytics) \PHPUnit_Framework_Assert::assertEquals( true, $configAnalytics->getAnalyticsForm()->getAnalyticsVerticalScope(), - 'Magento Analytics vertical scope is not website' + 'Magento Advanced Reporting industry scope is not website' ); } @@ -34,6 +34,6 @@ public function processAssert(ConfigAnalytics $configAnalytics) */ public function toString() { - return 'Magento Analytics vertical scope is website'; + return 'Magento Advanced Reporting industry scope is website'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyIndustryCanNotBeSaved.php similarity index 64% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyIndustryCanNotBeSaved.php index 3cf503047e6ea..5e86c13b8bbae 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyIndustryCanNotBeSaved.php @@ -9,12 +9,12 @@ use Magento\Analytics\Test\Page\Adminhtml\ConfigAnalytics; /** - * Assert Analytics empty Vertical can not be saved in Stores > Configuration > General > Analytics > General menu. + * Assert empty industry can not be saved in advanced reporting configuration. */ -class AssertEmptyVerticalCanNotBeSaved extends AbstractConstraint +class AssertEmptyIndustryCanNotBeSaved extends AbstractConstraint { /** - * Assert Analytics empty Vertical can not be saved in Stores > Configuration > General > Analytics > General menu. + * Assert empty industry can not be saved in Advanced Reporting configuration. * * @param ConfigAnalytics $configAnalytics * @param string $errorMessage @@ -25,7 +25,7 @@ public function processAssert(ConfigAnalytics $configAnalytics, $errorMessage) \PHPUnit_Framework_Assert::assertEquals( $errorMessage, $configAnalytics->getMessages()->getErrorMessage(), - 'There is no error message when saving empty vertical in configuration' + 'There is no error message when saving empty industry in configuration' ); } @@ -37,6 +37,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, $errorMessage) public function toString() { return - 'Empty Magento Analytics vertical can not be saved'; + 'Empty Magento Advanced Reporting industry can not be saved'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertIndustryIsSet.php similarity index 62% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertIndustryIsSet.php index 514c83a30ff51..635c4b35324ed 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertIndustryIsSet.php @@ -9,23 +9,23 @@ use Magento\Analytics\Test\Page\Adminhtml\ConfigAnalytics; /** - * Assert Analytics Vertical is set in Stores > Configuration > General > Analytics > General menu. + * Assert Advance Reporting Industry is set. */ -class AssertVerticalIsSet extends AbstractConstraint +class AssertIndustryIsSet extends AbstractConstraint { /** - * Assert Analytics Vertical is set in Stores > Configuration > General > Analytics > General menu. + * Assert Advance Reporting Industry is set * * @param ConfigAnalytics $configAnalytics - * @param string $vertical + * @param string $industry * @return void */ - public function processAssert(ConfigAnalytics $configAnalytics, $vertical) + public function processAssert(ConfigAnalytics $configAnalytics, $industry) { \PHPUnit_Framework_Assert::assertEquals( - $vertical, + $industry, $configAnalytics->getAnalyticsForm()->getAnalyticsVertical(), - $vertical . 'vertical is not selected' + $industry . 'industry is not selected' ); } @@ -37,6 +37,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, $vertical) public function toString() { return - 'Proper Magento Analytics vertical is selected'; + 'Proper Magento Advanced Reporting industry is selected'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php similarity index 95% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php index a721774f4d22c..0ff682c09c662 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php @@ -18,7 +18,7 @@ * * @ZephyrId MAGETWO-63898 */ -class SetVerticalTest extends Injectable +class SetIndustryTest extends Injectable { /* tags */ const MVP = 'no'; diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml similarity index 86% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml rename to dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml index 1db31781ccc2f..e44b83dbd55d1 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml @@ -6,16 +6,16 @@ */ --> - + Apps and Games - - + + --Please Select-- Please select a vertical. - + From ff3b1fa67d34925eb22b4b72ba4a7b22cd7f7047 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 12:09:12 -0500 Subject: [PATCH 028/194] MAGETWO-80480: Automate function tests - automate MAGETWO-80760 --- ...onBlock.php => AdvancedReportingBlock.php} | 17 ++++---- .../AssertAdvancedReportingPopupExist.php | 39 +++++++++++++++++++ .../Test/Page/Adminhtml/Dashboard.xml | 2 +- .../Analytics/Test/TestCase/InstallTest.xml | 17 ++++++++ 4 files changed, 64 insertions(+), 11 deletions(-) rename dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/{SubscriptionBlock.php => AdvancedReportingBlock.php} (54%) create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPopupExist.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/AdvancedReportingBlock.php similarity index 54% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/AdvancedReportingBlock.php index e362d51790a76..5bd381dfe2b3d 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/AdvancedReportingBlock.php @@ -5,30 +5,27 @@ */ namespace Magento\Analytics\Test\Block\Adminhtml\Dashboard\AdvancedReporting; -use Magento\Mtf\Client\Locator; use Magento\Ui\Test\Block\Adminhtml\Modal; /** - * Subscription block. + * Advanced Reporting block. */ -class SubscriptionBlock extends Modal +class AdvancedReportingBlock extends Modal { /** - * Close subscription pop-up button + * Close pop-up button * * @var string */ private $closeReportingButton = '[data-index="analytics_subscription_button_close"]'; /** - * Skip subscription popup. - * - * @return void + * @inheritdoc */ - public function skipAdvancedReporting() + public function isVisible() { $this->waitModalAnimationFinished(); - $this->_rootElement->find($this->closeReportingButton)->click(); - $this->waitForElementNotVisible($this->loadingMask); + return parent::isVisible() && $this->_rootElement->find($this->closeReportingButton)->isVisible(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPopupExist.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPopupExist.php new file mode 100644 index 0000000000000..cfb69094ce87c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPopupExist.php @@ -0,0 +1,39 @@ +getAdvancedReportingBlock()->isVisible(), + "Advanced Reporting Popup is absent on dashboard." + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return "Advanced Reporting Popup is visible on dashboard."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml index bc94ef7862ca7..e1631f20dd101 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml @@ -7,7 +7,7 @@ --> - + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml new file mode 100644 index 0000000000000..5ce0a2f1556fd --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml @@ -0,0 +1,17 @@ + + + + + + severity:S1 + + + + + + From d6ad3b0d1eed023f714387f112a8085d5615c848 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 13:00:09 -0500 Subject: [PATCH 029/194] MAGETWO-80480: Automate function tests - automate MAGETWO-80786 --- ...ificationMenuAccessUserPermissionsTest.php | 37 +++++++++++++++++++ ...ificationMenuAccessUserPermissionsTest.xml | 15 ++++++++ .../Magento/Analytics/Test/etc/testcase.xml | 2 +- 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.php new file mode 100644 index 0000000000000..2abbec4020e72 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.php @@ -0,0 +1,37 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml new file mode 100644 index 0000000000000..433e6b18b39e5 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml @@ -0,0 +1,15 @@ + + + + + + custom_admin_with_role_without_subscription_permissions + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml index 2de77423c0a74..dfdbdf0d7d761 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml @@ -6,7 +6,7 @@ */ --> - + From 941bca0dd10c51b6cc2168c16f342ce2e23e894d Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Tue, 10 Oct 2017 13:35:43 -0500 Subject: [PATCH 030/194] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- .../Analytics/Test/Unit/Model/NotificationFlagManagerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php index 3061ec98e6b1a..43e160bfcbb22 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php @@ -45,7 +45,7 @@ public function testSetNotifiedUser() $this->flagManagerMock ->expects($this->once()) ->method('saveFlag') - ->with(NotificationFlagManager::NOTIFICATION_SEEN . $userId, 1) + ->with('analytics_notification_seen_admin_' . $userId, 1) ->willReturn(true); $this->assertTrue($this->notificationFlagManager->setNotifiedUser($userId)); } @@ -56,7 +56,7 @@ public function testIsUserNotified() $this->flagManagerMock ->expects($this->once()) ->method('getFlagData') - ->with(NotificationFlagManager::NOTIFICATION_SEEN . $userId) + ->with('analytics_notification_seen_admin_' . $userId) ->willReturn(true); $this->assertTrue($this->notificationFlagManager->isUserNotified($userId)); } From 9d6a8135a302457737a7e43d39756c4b23b2b33b Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Tue, 10 Oct 2017 13:58:40 -0500 Subject: [PATCH 031/194] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- .../Test/Unit/Model/NotificationFlagManagerTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php index 43e160bfcbb22..0ac331c8d1015 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php @@ -8,7 +8,7 @@ use Magento\Analytics\Model\NotificationFlagManager; use Magento\Framework\FlagManager; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; /** * Class NotificationFlagManagerTest @@ -30,8 +30,8 @@ public function setUp() $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) ->disableOriginalConstructor() ->getMock(); - $objectManagerHelper = new ObjectManagerHelper($this); - $this->notificationFlagManager = $objectManagerHelper->getObject( + $objectManager = new ObjectManager($this); + $this->notificationFlagManager = $objectManager->getObject( NotificationFlagManager::class, [ 'flagManager' => $this->flagManagerMock From 810aac28ffb49c7a90928e9cb94cb303d9627da0 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 15:40:13 -0500 Subject: [PATCH 032/194] MAGETWO-80477: Update Advanced Reporting Subscription Popup - fix unit test --- .../Dashboard/AdvancedReporting/AdvancedReportingBlock.php | 1 - 1 file changed, 1 deletion(-) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/AdvancedReportingBlock.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/AdvancedReportingBlock.php index 5bd381dfe2b3d..1d6ac74e7ffec 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/AdvancedReportingBlock.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/AdvancedReportingBlock.php @@ -26,6 +26,5 @@ public function isVisible() { $this->waitModalAnimationFinished(); return parent::isVisible() && $this->_rootElement->find($this->closeReportingButton)->isVisible(); - } } From 14d70f763ea2406cf60c94c0a969da4f08f100d3 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 15:41:10 -0500 Subject: [PATCH 033/194] MAGETWO-80480: Automate function tests - fix static test failure --- .../Test/Unit/Model/NotificationFlagManagerTest.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php index 0ac331c8d1015..e3be87843d131 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php @@ -42,8 +42,7 @@ public function setUp() public function testSetNotifiedUser() { $userId = 1; - $this->flagManagerMock - ->expects($this->once()) + $this->flagManagerMock->expects($this->once()) ->method('saveFlag') ->with('analytics_notification_seen_admin_' . $userId, 1) ->willReturn(true); @@ -53,8 +52,7 @@ public function testSetNotifiedUser() public function testIsUserNotified() { $userId = 1; - $this->flagManagerMock - ->expects($this->once()) + $this->flagManagerMock->expects($this->once()) ->method('getFlagData') ->with('analytics_notification_seen_admin_' . $userId) ->willReturn(true); From e26da7718370b17b94ea8ca42a1997bf29aba3d3 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 16:29:10 -0500 Subject: [PATCH 034/194] MAGETWO-80480: Automate function tests - automate MAGETWO-80786 --- ...ginAgainAdvancedReportingPopupNotExist.php | 49 +++++++++++++++++++ ...ificationMenuAccessUserPermissionsTest.xml | 6 +++ 2 files changed, 55 insertions(+) create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php new file mode 100644 index 0000000000000..65b706e7291fe --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php @@ -0,0 +1,49 @@ +objectManager->create( + \Magento\User\Test\TestStep\LogoutUserOnBackendStep::class + )->run(); + + + $this->objectManager->create( + \Magento\User\Test\TestStep\LoginUserOnBackendStep::class, + ['user' => $user] + )->run(); + \PHPUnit_Framework_Assert::assertFalse( + $dashboard->getAdvancedReportingBlock()->isVisible(), + "Advanced Reporting Popup is visible on dashboard." + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return "Advanced Reporting Popup is absent on dashboard."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml index 433e6b18b39e5..57ca2a2473b32 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml @@ -10,6 +10,12 @@ custom_admin_with_role_without_subscription_permissions + + + + default + + From bc33fb4f6a4512ca2e07ac3b6bd7e9cd17f3fe1d Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 16:34:25 -0500 Subject: [PATCH 035/194] MAGETWO-80477: Update Advanced Reporting Subscription Popup - fix unit test --- .../Test/Unit/Model/Condition/CanViewNotificationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index 45a30ea1113a7..c0941a5a94e9e 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -8,7 +8,7 @@ use Magento\Analytics\Model\Condition\CanViewNotification; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Analytics\Model\notificationFlagManager; +use Magento\Analytics\Model\NotificationFlagManager; use Magento\Backend\Model\Auth\Session; /** From 7bfa39a4c4d1b1b226c1781d5a37337973b10c6c Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 16:43:49 -0500 Subject: [PATCH 036/194] MAGETWO-80480: Automate function tests - automate MAGETWO-80786 --- .../AssertLoginAgainAdvancedReportingPopupNotExist.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php index 65b706e7291fe..cf22df718149b 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php @@ -12,7 +12,7 @@ /** * Assert that Advanced Reporting Popup is absent on dashboard when admin user login again */ -class AssertAdvancedReportingPopupExist extends AbstractConstraint +class AssertLoginAgainAdvancedReportingPopupNotExist extends AbstractConstraint { /** * Assert that Advanced Reporting Popup is absent on dashboard when admin user login again @@ -26,11 +26,11 @@ public function processAssert(Dashboard $dashboard, User $user) \Magento\User\Test\TestStep\LogoutUserOnBackendStep::class )->run(); - $this->objectManager->create( \Magento\User\Test\TestStep\LoginUserOnBackendStep::class, ['user' => $user] )->run(); + \PHPUnit_Framework_Assert::assertFalse( $dashboard->getAdvancedReportingBlock()->isVisible(), "Advanced Reporting Popup is visible on dashboard." From 891e58fe0be4307c1485696f7ca33281e524c499 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 17:27:43 -0500 Subject: [PATCH 037/194] MAGETWO-80480: Automate function tests - automate MAGETWO-80786 --- ...ssertAdvancedReportingSectionInvisible.php | 40 +++++++++++++++++++ .../AssertAdvancedReportingSectionVisible.php | 40 +++++++++++++++++++ ...ificationMenuAccessUserPermissionsTest.xml | 2 + 3 files changed, 82 insertions(+) create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionInvisible.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionVisible.php diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionInvisible.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionInvisible.php new file mode 100644 index 0000000000000..d154ee275710a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionInvisible.php @@ -0,0 +1,40 @@ +open(); + \PHPUnit_Framework_Assert::assertFalse( + in_array('Advanced Reporting', $configEdit->getTabs()->getSubTabsNames('General')), + 'Advanced Reporting section is visible.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Advanced Reporting section is invisible.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionVisible.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionVisible.php new file mode 100644 index 0000000000000..18ea93fee1ea3 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionVisible.php @@ -0,0 +1,40 @@ +open(); + \PHPUnit_Framework_Assert::assertTrue( + in_array('Advanced Reporting', $configEdit->getTabs()->getSubTabsNames('General')), + 'Advanced Reporting section is not visible.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Advanced Reporting section is visible.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml index 57ca2a2473b32..0a827cacc984c 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml @@ -11,11 +11,13 @@ custom_admin_with_role_without_subscription_permissions + default + From db7dbd4f8d3a817224ad42f17793f2ecc0bb69a1 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 20:32:58 -0500 Subject: [PATCH 038/194] MAGETWO-80480: Automate function tests - fix function test failure --- .../app/Magento/Analytics/Test/TestCase/SetIndustryTest.php | 6 +++--- .../app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php index 0ff682c09c662..8b76df048b9a4 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php @@ -28,13 +28,13 @@ class SetIndustryTest extends Injectable * Set analytics vertical test. * * @param ConfigAnalytics $configAnalytics - * @param string $vertical + * @param string $industry * @return void */ - public function test(ConfigAnalytics $configAnalytics, $vertical) + public function test(ConfigAnalytics $configAnalytics, $industry) { $configAnalytics->open(); - $configAnalytics->getAnalyticsForm()->setAnalyticsVertical($vertical); + $configAnalytics->getAnalyticsForm()->setAnalyticsVertical($industry); $configAnalytics->getAnalyticsForm()->saveConfig(); } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml index e44b83dbd55d1..bb21a2adf130c 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml @@ -8,12 +8,12 @@ - Apps and Games + Apps and Games - --Please Select-- + --Please Select-- Please select a vertical. From 4cdc13319ae5dccef8973ee04ac4bf2c5fe9f0a9 Mon Sep 17 00:00:00 2001 From: Tim Bezhashvyly Date: Wed, 11 Oct 2017 08:06:16 +0200 Subject: [PATCH 039/194] Issue #6924: Unmask exception message during product import Probably a typo. Exception message was passed as a exception description argument instead of exception message. Artefact of optional parameters. --- app/code/Magento/ImportExport/Model/Import.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/ImportExport/Model/Import.php b/app/code/Magento/ImportExport/Model/Import.php index 8da1bb1763ece..092b721b82435 100644 --- a/app/code/Magento/ImportExport/Model/Import.php +++ b/app/code/Magento/ImportExport/Model/Import.php @@ -567,7 +567,6 @@ public function validateSource(\Magento\ImportExport\Model\Import\AbstractSource ProcessingError::ERROR_LEVEL_CRITICAL, null, null, - null, $e->getMessage() ); } From 25e7e1432aad71d32cbc36289c8dc0c42611cb94 Mon Sep 17 00:00:00 2001 From: Joan He Date: Wed, 11 Oct 2017 09:44:42 -0500 Subject: [PATCH 040/194] MAGETWO-80480: Automate function tests - address code review comments --- .../app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml index bb21a2adf130c..3a04420ca9d64 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml @@ -6,13 +6,13 @@ */ --> - - + + Apps and Games - + --Please Select-- Please select a vertical. From 4ab424f4145ceed93f287f62eb96081604a9874b Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 11 Oct 2017 10:25:49 -0500 Subject: [PATCH 041/194] MAGETWO-80481: Update documents --- app/code/Magento/Analytics/README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Analytics/README.md b/app/code/Magento/Analytics/README.md index ee6d017a1f3ac..7ec64abcd9b86 100644 --- a/app/code/Magento/Analytics/README.md +++ b/app/code/Magento/Analytics/README.md @@ -1,4 +1,4 @@ -# Magento_Analytics module +# Magento_Analytics Module The Magento_Analytics module integrates your Magento instance with the [Magento Business Intelligence (MBI)](https://magento.com/products/business-intelligence) to use [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html) functionality. @@ -20,6 +20,22 @@ Beyond the [usual module file structure](http://devdocs.magento.com/guides/v2.2/ [Report XML](http://devdocs.magento.com/guides/v2.2/advanced-reporting/report-xml.html) is a markup language used to build reports for Advanced Reporting. The language declares SQL queries using XML declaration. +## Subscription Process + +The subscription to the MBI service is enabled during the installation process of the Analytics module. Each administrator will be notified of these new features upon their initial login to the Admin Panel. + +## Analytics Settings + +Configuration settings for the Analytics module can be modified in the Admin Panel on the Stores > Configuration page under the General > Advanced Reporting tab. + +The following options can be adjusted: +* Advanced Reporting Service (Enabled/Disabled) + * Alters the status of the Advanced Reporting subscription +* Time of day to send data (Hour/Minute/Second in the store's time zone) + * Defines when the data collection process for the Advanced Reporting service occurs +* Industry + * Defines the industry of the store in order to create a personalized Advanced Reporting experience + ## Extensibility We do not recommend to extend the Magento_Analytics module. It introduces an API that is purposed to transfer the collected data. Note that the API cannot be used for other needs. From 6e0909ff4320d198cad853dd10c19588d3519994 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 11 Oct 2017 10:35:36 -0500 Subject: [PATCH 042/194] MAGETWO-81342: Update link URLs to subscription modal and configuration page --- .../Analytics/etc/adminhtml/system.xml | 3 +- app/code/Magento/Analytics/i18n/en_US.csv | 52 +++++++++---------- .../analytics_subscription_notification.xml | 3 +- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/app/code/Magento/Analytics/etc/adminhtml/system.xml b/app/code/Magento/Analytics/etc/adminhtml/system.xml index c3bf5c4b11d2f..889517e629e04 100644 --- a/app/code/Magento/Analytics/etc/adminhtml/system.xml +++ b/app/code/Magento/Analytics/etc/adminhtml/system.xml @@ -15,7 +15,8 @@ For more information, see our terms and conditions.]]> + "Go to Advanced Reporting" link.
For more information, see our + terms and conditions.]]> Magento\Config\Model\Config\Source\Enabledisable diff --git a/app/code/Magento/Analytics/i18n/en_US.csv b/app/code/Magento/Analytics/i18n/en_US.csv index 090534923e450..b1c7ffe45518f 100644 --- a/app/code/Magento/Analytics/i18n/en_US.csv +++ b/app/code/Magento/Analytics/i18n/en_US.csv @@ -34,13 +34,14 @@ 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." +"This service provides a dynamic suite of reports with rich insights about your business. + Your reports can be accessed securely on a personalized dashboard outside of the admin panel by clicking on the + ""Go to Advanced Reporting"" link.
For more information, see our + terms and conditions. + ","This service provides a dynamic suite of reports with rich insights about your business. + Your reports can be accessed securely on a personalized dashboard outside of the admin panel by clicking on the + ""Go to Advanced Reporting"" link.
For more information, 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" @@ -70,26 +71,22 @@ Industry,Industry "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.

+"

Advanced Reporting + provides you with a dynamic suite of reports with rich insights about the health of your + business.


As part of the Advanced Reporting service, we may also use your customer + data for such purposes as benchmarking, improving our products and services, and providing you + with new and improved analytics.


By using Magento 2.2, you agree to the Advanced + Reporting Privacy Policy and + Terms + of Service. You may opt out at any time from the Stores Configuration page.

+ ","

Advanced Reporting + provides you with a dynamic suite of reports with rich insights about the health of your + business.


As part of the Advanced Reporting service, we may also use your customer + data for such purposes as benchmarking, improving our products and services, and providing you + with new and improved analytics.


By using Magento 2.2, you agree to the Advanced + Reporting Privacy Policy and + Terms + of Service. You may opt out at any time from the Stores Configuration page.

" "Are you sure you want to opt out?","Are you sure you want to opt out?" Cancel,Cancel @@ -101,3 +98,4 @@ Cancel,Cancel 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.

" +"In order to personalize your Advanced Reporting experience, please select your industry.","In order to personalize your Advanced Reporting experience, please select your industry." diff --git a/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml b/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml index c26b4e15dfe17..93c8b7b8c5ef4 100644 --- a/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml +++ b/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml @@ -63,7 +63,8 @@ business.


As part of the Advanced Reporting service, we may also use your customer data for such purposes as benchmarking, improving our products and services, and providing you with new and improved analytics.


By using Magento 2.2, you agree to the Advanced - Reporting Privacy Policy and Terms + Reporting Privacy Policy + and Terms of Service. You may opt out at any time from the Stores Configuration page.

]]> From 1645894da2b76f4e0f31e2c1aecedb3c7795dbbf Mon Sep 17 00:00:00 2001 From: Joan He Date: Wed, 11 Oct 2017 22:29:54 -0500 Subject: [PATCH 043/194] MAGETWO-80480: Automate function tests - fix function test failures --- .../tests/app/Magento/Analytics/Test/Repository/Role.xml | 7 +++++++ .../TestCase/NotificationMenuAccessUserPermissionsTest.xml | 2 +- .../tests/app/Magento/Analytics/Test/etc/testcase.xml | 3 +-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml index 6d067a691d59d..77cc8b5fac038 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml @@ -13,6 +13,13 @@ %current_password% Magento_Backend::dashboard + Magento_Backend::stores + Magento_Config::config + Magento_Config::config_general + Magento_Backend::system + Magento_Backend::system_other_settings + Magento_AdminNotification::adminnotification + Magento_AdminNotification::show_list diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml index 0a827cacc984c..794f9e2d5da27 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml @@ -14,7 +14,7 @@ - default + custom_admin_with_default_role diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml index dfdbdf0d7d761..ce1828c8adf5c 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml @@ -8,7 +8,6 @@ - - + From 9ee464c765ac843e10235db9e619cb66e8cbee1f Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Thu, 12 Oct 2017 09:55:57 +0200 Subject: [PATCH 044/194] Fix for #9566: Show the correct label in the admin --- app/code/Magento/Sales/Model/Order/Config.php | 8 +++- .../Magento/Sales/Model/Order/StatusTest.php | 48 +++++++++++++++++++ .../Magento/Sales/_files/order_status.php | 25 ++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_status.php diff --git a/app/code/Magento/Sales/Model/Order/Config.php b/app/code/Magento/Sales/Model/Order/Config.php index 1c7514142678b..ae0ef0c828512 100644 --- a/app/code/Magento/Sales/Model/Order/Config.php +++ b/app/code/Magento/Sales/Model/Order/Config.php @@ -122,8 +122,14 @@ public function getStateDefaultStatus($state) */ public function getStatusLabel($code) { - $code = $this->maskStatusForArea($this->state->getAreaCode(), $code); + $area = $this->state->getAreaCode(); + $code = $this->maskStatusForArea($area, $code); $status = $this->orderStatusFactory->create()->load($code); + + if ($area == 'adminhtml') { + return $status->getLabel(); + } + return $status->getStoreLabel(); } diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php new file mode 100644 index 0000000000000..d53ff46122f57 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php @@ -0,0 +1,48 @@ +get(\Magento\Framework\App\State::class)->setAreaCode('adminhtml'); + + /** @var \Magento\Sales\Model\Order $order */ + $order = $objectManager->create(\Magento\Sales\Model\Order::class); + $order->loadByIncrementId('100000001'); + + $this->assertEquals('Example', $order->getStatusLabel()); + } + + /** + * In the frontend the store view specific label must be showed. + * + * @magentoDataFixture Magento/Sales/_files/order_status.php + */ + public function testTheStoreViewLabelIsUsedInTheFrontend() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $objectManager->get(\Magento\Framework\App\State::class)->setAreaCode('frontend'); + + /** @var \Magento\Sales\Model\Order $order */ + $order = $objectManager->create(\Magento\Sales\Model\Order::class); + $order->loadByIncrementId('100000001'); + + $this->assertEquals('Store view example', $order->getStatusLabel()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_status.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_status.php new file mode 100644 index 0000000000000..e65dd6b682396 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_status.php @@ -0,0 +1,25 @@ +create( + \Magento\Sales\Model\Order\Status::class +); + +$data = [ + 'status' => 'example', + 'label' => 'Example', + 'store_labels' => [ + 1 => 'Store view example', + ] +]; + +$orderStatus->setData($data)->setStatus('example'); +$orderStatus->save(); + +$order->setStatus('example'); +$order->save(); From aeb0be09cf2efeecdc6b05cc58181e7b6a5d5596 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Thu, 12 Oct 2017 15:44:15 -0500 Subject: [PATCH 045/194] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- app/code/Magento/Advertisement/LICENSE.txt | 48 ++++ .../Magento/Advertisement/LICENSE_AFL.txt | 48 ++++ .../Model/AdvertisementFlagManager.php | 60 +++++ .../Model/Condition/CanViewNotification.php | 72 ++++++ app/code/Magento/Advertisement/README.md | 9 + .../Model/AdvertisementFlagManagerTest.php | 61 +++++ .../Condition/CanViewNotificationTest.php | 84 +++++++ .../Ui/DataProvider/DummyDataProvider.php | 237 ++++++++++++++++++ app/code/Magento/Advertisement/composer.json | 24 ++ app/code/Magento/Advertisement/etc/module.xml | 15 ++ .../Magento/Advertisement/registration.php | 11 + .../layout/adminhtml_dashboard_index.xml | 26 ++ .../layout/adminhtml_dashboard_index_test.xml | 80 ++++++ .../advertisement_notification.xml | 112 +++++++++ .../ui_component/analytics_notification.xml | 116 +++++++++ .../ui_component/b2b_notification.xml | 122 +++++++++ .../developer_experience_notification.xml | 120 +++++++++ .../web/css/source/_module.less | 114 +++++++++ .../web/images/analytics-icon.svg | 84 +++++++ .../web/images/b2b-icon.svg | 60 +++++ .../web/images/developer-experience-icon.svg | 28 +++ 21 files changed, 1531 insertions(+) create mode 100644 app/code/Magento/Advertisement/LICENSE.txt create mode 100644 app/code/Magento/Advertisement/LICENSE_AFL.txt create mode 100644 app/code/Magento/Advertisement/Model/AdvertisementFlagManager.php create mode 100644 app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php create mode 100644 app/code/Magento/Advertisement/README.md create mode 100644 app/code/Magento/Advertisement/Test/Unit/Model/AdvertisementFlagManagerTest.php create mode 100644 app/code/Magento/Advertisement/Test/Unit/Model/Condition/CanViewNotificationTest.php create mode 100644 app/code/Magento/Advertisement/Ui/DataProvider/DummyDataProvider.php create mode 100644 app/code/Magento/Advertisement/composer.json create mode 100644 app/code/Magento/Advertisement/etc/module.xml create mode 100644 app/code/Magento/Advertisement/registration.php create mode 100644 app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index.xml create mode 100644 app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index_test.xml create mode 100644 app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml create mode 100644 app/code/Magento/Advertisement/view/adminhtml/ui_component/analytics_notification.xml create mode 100644 app/code/Magento/Advertisement/view/adminhtml/ui_component/b2b_notification.xml create mode 100644 app/code/Magento/Advertisement/view/adminhtml/ui_component/developer_experience_notification.xml create mode 100644 app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less create mode 100644 app/design/adminhtml/Magento/backend/Magento_Advertisement/web/images/analytics-icon.svg create mode 100644 app/design/adminhtml/Magento/backend/Magento_Advertisement/web/images/b2b-icon.svg create mode 100644 app/design/adminhtml/Magento/backend/Magento_Advertisement/web/images/developer-experience-icon.svg diff --git a/app/code/Magento/Advertisement/LICENSE.txt b/app/code/Magento/Advertisement/LICENSE.txt new file mode 100644 index 0000000000000..49525fd99da9c --- /dev/null +++ b/app/code/Magento/Advertisement/LICENSE.txt @@ -0,0 +1,48 @@ + +Open Software License ("OSL") v. 3.0 + +This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Open Software License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/Advertisement/LICENSE_AFL.txt b/app/code/Magento/Advertisement/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/Advertisement/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/Advertisement/Model/AdvertisementFlagManager.php b/app/code/Magento/Advertisement/Model/AdvertisementFlagManager.php new file mode 100644 index 0000000000000..88a95f5df63b1 --- /dev/null +++ b/app/code/Magento/Advertisement/Model/AdvertisementFlagManager.php @@ -0,0 +1,60 @@ +flagManager = $flagManager; + } + + /** + * Sets the flag to indicate the user was notified about Analytic services + * @param $userId + * @return bool + */ + public function setNotifiedUser($userId) + { + $flagCode = self::NOTIFICATION_SEEN . $userId; + return $this->flagManager->saveFlag($flagCode, 1); + } + + /** + * Returns the flag data if the user was notified about Analytic services + * @param $userId + * @return bool + */ + public function isUserNotified($userId) + { + if ($this->flagManager->getFlagData(self::NOTIFICATION_SEEN . $userId)) { + return true; + } + + return false; + } +} diff --git a/app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php b/app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php new file mode 100644 index 0000000000000..e85ec3a3fce20 --- /dev/null +++ b/app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php @@ -0,0 +1,72 @@ +advertisementFlagManager = $advertisementFlagManager; + $this->session = $session; + } + + /** + * Validate if notification popup can be shown and set the notification flag + * + * @inheritdoc + */ + public function isVisible(array $arguments) + { + $userId = $this->session->getUser()->getId(); + if ($this->advertisementFlagManager->isUserNotified($userId)) { + return false; + } + + //return $this->advertisementFlagManager->setNotifiedUser($userId); + return true; + } + + /** + * @return string + */ + public function getName() + { + return self::NAME; + } +} diff --git a/app/code/Magento/Advertisement/README.md b/app/code/Magento/Advertisement/README.md new file mode 100644 index 0000000000000..9a020241c628b --- /dev/null +++ b/app/code/Magento/Advertisement/README.md @@ -0,0 +1,9 @@ +# Magento_Advertisement Module + +This module serves to show each administrator user new features of a Magento installation or upgrade. + +The module implements the following functionality: + +* Shows a modal pop-up with a high level overview of the features included in a new release of Magento upon the initial login of each admin user to the Admin Panel +* The modal is enabled with pagination functionality to allow for previous and next navigation to each modal page +* Each modal page includes more information about a highlighted feature of the Magento release diff --git a/app/code/Magento/Advertisement/Test/Unit/Model/AdvertisementFlagManagerTest.php b/app/code/Magento/Advertisement/Test/Unit/Model/AdvertisementFlagManagerTest.php new file mode 100644 index 0000000000000..ddcbdbd6c1a0b --- /dev/null +++ b/app/code/Magento/Advertisement/Test/Unit/Model/AdvertisementFlagManagerTest.php @@ -0,0 +1,61 @@ +flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManager = new ObjectManager($this); + $this->advertisementFlagManager = $objectManager->getObject( + AdvertisementFlagManager::class, + [ + 'flagManager' => $this->flagManagerMock + ] + ); + } + + public function testSetNotifiedUser() + { + $userId = 1; + $this->flagManagerMock->expects($this->once()) + ->method('saveFlag') + ->with('advertisement_notification_seen_admin_' . $userId, 1) + ->willReturn(true); + $this->assertTrue($this->advertisementFlagManager->setNotifiedUser($userId)); + } + + public function testIsUserNotified() + { + $userId = 1; + $this->flagManagerMock->expects($this->once()) + ->method('getFlagData') + ->with('advertisement_notification_seen_admin_' . $userId) + ->willReturn(true); + $this->assertTrue($this->advertisementFlagManager->isUserNotified($userId)); + } +} diff --git a/app/code/Magento/Advertisement/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Advertisement/Test/Unit/Model/Condition/CanViewNotificationTest.php new file mode 100644 index 0000000000000..3fe6b6609bd5c --- /dev/null +++ b/app/code/Magento/Advertisement/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -0,0 +1,84 @@ +advertisementFlagManagerMock = $this->getMockBuilder(AdvertisementFlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->sessionMock = $this->getMockBuilder(Session::class) + ->disableOriginalConstructor() + ->setMethods(['getUser', 'getId']) + ->getMock(); + $objectManager = new ObjectManager($this); + $this->canViewNotification = $objectManager->getObject( + CanViewNotification::class, + [ + 'advertisementFlagManager' => $this->advertisementFlagManagerMock, + 'session' => $this->sessionMock + ] + ); + } + + public function isVisibleProvider() + { + return [ + [1, false, true], + [1, true, false] + ]; + } + + /** + * @dataProvider isVisibleProvider + * @param int $userId + * @param bool $isUserNotified + * @param bool $expected + */ + public function testIsVisible($userId, $isUserNotified, $expected) + { + $this->sessionMock->expects($this->once()) + ->method('getUser') + ->willReturnSelf(); + $this->sessionMock->expects($this->once()) + ->method('getId') + ->willReturn($userId); + $this->advertisementFlagManagerMock->expects($this->once()) + ->method('isUserNotified') + ->willReturn($isUserNotified); + $this->advertisementFlagManagerMock->expects($this->any()) + ->method('setNotifiedUser') + ->willReturn(true); + + $this->assertEquals($expected, $this->canViewNotification->isVisible([])); + } +} diff --git a/app/code/Magento/Advertisement/Ui/DataProvider/DummyDataProvider.php b/app/code/Magento/Advertisement/Ui/DataProvider/DummyDataProvider.php new file mode 100644 index 0000000000000..7af053190645a --- /dev/null +++ b/app/code/Magento/Advertisement/Ui/DataProvider/DummyDataProvider.php @@ -0,0 +1,237 @@ +name = $name; + $this->searchResult = $searchResult; + $this->searchCriteria = $searchCriteria; + $this->collection = $collection; + $this->data = $data; + } + + /** + * Get Data Provider name + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Get config data + * + * @return mixed + */ + public function getConfigData() + { + return isset($this->data['config']) ? $this->data['config'] : []; + } + + /** + * Set config data + * + * @param mixed $config + * + * @return bool + */ + public function setConfigData($config) + { + $this->data['config'] = $config; + + return true; + } + + /** + * @return array + */ + public function getMeta() + { + return []; + } + + /** + * @param string $fieldSetName + * @param string $fieldName + * + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function getFieldMetaInfo($fieldSetName, $fieldName) + { + return []; + } + + /** + * Get field set meta info + * + * @param string $fieldSetName + * + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function getFieldSetMetaInfo($fieldSetName) + { + return []; + } + + /** + * @param string $fieldSetName + * + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function getFieldsMetaInfo($fieldSetName) + { + return []; + } + + /** + * Get primary field name + * + * @return string + */ + public function getPrimaryFieldName() + { + return ''; + } + + /** + * Get field name in request + * + * @return string + */ + public function getRequestFieldName() + { + return ''; + } + + /** + * Get data + * + * @return mixed + */ + public function getData() + { + return $this->collection->toArray(); + } + + /** + * Add field filter to collection + * + * @param \Magento\Framework\Api\Filter $filter + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function addFilter(\Magento\Framework\Api\Filter $filter) + { + } + + /** + * Add ORDER BY to the end or to the beginning + * + * @param string $field + * @param string $direction + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function addOrder($field, $direction) + { + } + + /** + * Set Query limit + * + * @param int $offset + * @param int $size + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function setLimit($offset, $size) + { + } + + /** + * Returns search criteria + * + * @return SearchCriteriaInterface + */ + public function getSearchCriteria() + { + return $this->searchCriteria; + } + + /** + * @return SearchResultInterface + */ + public function getSearchResult() + { + return $this->searchResult; + } +} diff --git a/app/code/Magento/Advertisement/composer.json b/app/code/Magento/Advertisement/composer.json new file mode 100644 index 0000000000000..93660553a3cff --- /dev/null +++ b/app/code/Magento/Advertisement/composer.json @@ -0,0 +1,24 @@ +{ + "name": "magento/module-advertisement", + "description": "N/A", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/module-backend": "100.2.*", + "magento/module-store": "100.2.*", + "magento/framework": "100.2.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\Advertisement\\": "" + } + } +} diff --git a/app/code/Magento/Advertisement/etc/module.xml b/app/code/Magento/Advertisement/etc/module.xml new file mode 100644 index 0000000000000..119951fcc66a8 --- /dev/null +++ b/app/code/Magento/Advertisement/etc/module.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/Advertisement/registration.php b/app/code/Magento/Advertisement/registration.php new file mode 100644 index 0000000000000..4e703b10342a8 --- /dev/null +++ b/app/code/Magento/Advertisement/registration.php @@ -0,0 +1,11 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index_test.xml b/app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index_test.xml new file mode 100644 index 0000000000000..72c562752516c --- /dev/null +++ b/app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index_test.xml @@ -0,0 +1,80 @@ + + + + + + + + + false + + 3333 + true + fieldset + advertisement_notification.advertisement_notification + advertisement_modal + advertisement-steps-wizard + data + + + + + + advertisement_notification.advertisement_notification + advertisement_modal + data + + + + + + advertisement_notification.advertisement_notification + advertisement_modal + product_attributes_listing.product_attributes_listing.product_attributes_columns.ids + advertisement_notification.advertisement_notification_data_source + data + + + + + + + + advertisement_notification.advertisement_notification + advertisement_modal + data + + + + + + + + advertisement_notification.advertisement_notification + advertisement_modal + data + + + + + + + + advertisement_notification.advertisement_notification + advertisement_modal + data + + + + + + + + + diff --git a/app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml b/app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml new file mode 100644 index 0000000000000..b1a2e3b1f709a --- /dev/null +++ b/app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml @@ -0,0 +1,112 @@ + + +
+ + + advertisement_notification.advertisement_notification_data_source + + Advertisement + templates/form/collapsible + + + advertisement_notification + true + simple + data + + advertisement_notification.advertisement_notification_data_source + + + + + + Magento_Ui/js/form/provider + + + + + + false + + + + + + + actionCancel + true + + + + + + + + + +
+ + + + + + + advertisement-text + Magento 2.2.2 offers an exciting set of features and enhancements, including:

+
+
+

Advanced Reporting

+

Gain valuable insights through a dynamic suite of product, order, and customer reports, + powered by Magento Business Intelligence.

+
+
+

Developer Experience

+

We've improved the entire development lifecycle - installation, development, and maintenance + - while ensuring Magento's commitment to quality.

+
+
+

Business-to-Business (B2B) Magento Commerce only

+

Features to manage your complex company accounts, rapid reordering, new buyers' roles and + permissions, and more.

+
+

Release notes and additional details can be found at + Magento DevDocs. +

]]> +
+
+
+
+ + + + + + + + +
+
+
diff --git a/app/code/Magento/Advertisement/view/adminhtml/ui_component/analytics_notification.xml b/app/code/Magento/Advertisement/view/adminhtml/ui_component/analytics_notification.xml new file mode 100644 index 0000000000000..267ed8ac665e1 --- /dev/null +++ b/app/code/Magento/Advertisement/view/adminhtml/ui_component/analytics_notification.xml @@ -0,0 +1,116 @@ + + +
+ + + advertisement_notification.advertisement_notification_data_source + + Analytics Subscription + templates/form/collapsible + + + advertisement_notification + true + simple + data + + advertisement_notification.advertisement_notification_data_source + + + + + + Magento_Ui/js/form/provider + + + + + + false + + + + + + + actionCancel + true + + + + + + + + + +
+ + + + + + + advertisement-text + Advanced Reporting + provides you with a dynamic suite of reports with rich insights about the health of your + business.


As part of the Advanced Reporting service, we may also use your customer + data for such purposes as benchmarking, improving our products and services, and providing you + with new and improved analytics.


By using Magento 2.2, you agree to the Advanced + Reporting Privacy Policy + and Terms + of Service. You may opt out at any time from the Stores Configuration page.

]]> +
+
+
+
+ + + + + + + + + +
+
+
diff --git a/app/code/Magento/Advertisement/view/adminhtml/ui_component/b2b_notification.xml b/app/code/Magento/Advertisement/view/adminhtml/ui_component/b2b_notification.xml new file mode 100644 index 0000000000000..0cd28487b1063 --- /dev/null +++ b/app/code/Magento/Advertisement/view/adminhtml/ui_component/b2b_notification.xml @@ -0,0 +1,122 @@ + + +
+ + + advertisement_notification.advertisement_notification_data_source + + Analytics Subscription + templates/form/collapsible + + + advertisement_notification + true + simple + data + + advertisement_notification.advertisement_notification_data_source + + + + + + Magento_Ui/js/form/provider + + + + + + false + + + + + + + actionCancel + true + + + + + + + + + +
+ + + + + + + advertisement-text + Magento Commerce 2.2.2 offers rich new functionality that empowers B2B merchants to transform + their online purchasing experience to achieve greater operational efficiency, improved customer + service, and sales growth. New capabilities include: +

+
    +
  • Company accounts with multiple tiers of buyers
  • +
  • Buyer roles and permissions
  • +
  • Custom catalogs and pricing
  • +
  • Quoting support
  • +
  • Rapid reorder experience
  • +
  • Payments on credit
  • +
]]> +
+
+
+
+ + + + + + + + + +
+
+
diff --git a/app/code/Magento/Advertisement/view/adminhtml/ui_component/developer_experience_notification.xml b/app/code/Magento/Advertisement/view/adminhtml/ui_component/developer_experience_notification.xml new file mode 100644 index 0000000000000..39ce179fe7255 --- /dev/null +++ b/app/code/Magento/Advertisement/view/adminhtml/ui_component/developer_experience_notification.xml @@ -0,0 +1,120 @@ + + +
+ + + advertisement_notification.advertisement_notification_data_source + + Analytics Subscription + templates/form/collapsible + + + advertisement_notification + true + simple + data + + advertisement_notification.advertisement_notification_data_source + + + + + + Magento_Ui/js/form/provider + + + + + + false + + + + + + + actionCancel + true + + + + + + + + + +
+ + + + + + + advertisement-text + Magento's 2.2.2 release offers a set of improvements that were developed using increased + quality standards. The release includes these features, among others: +

+
    +
  • GitHub Community Moderator Team
  • +
  • GitHub Community Videos
  • +
  • DevDocs Enhancements
  • +
+

Find the 2.2.2 details and future plans in the + Magento DevBlog. +

]]> +
+
+
+
+ + + + + + + + + +
+
+
diff --git a/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less new file mode 100644 index 0000000000000..b6b3a635ae2cb --- /dev/null +++ b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less @@ -0,0 +1,114 @@ +// /** +// * Copyright © Magento, Inc. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Magento_Advertisement Modal on dashboard +// --------------------------------------------- + +.advertisement-modal, .analytics-subscription-modal, .developer-experience-modal, .b2b-modal { + .modal-inner-wrap { + height: 50rem; + max-width: 75rem; + margin-top: 13rem; + + .modal-content, .modal-header { + padding-left: 4rem; + padding-right: 4rem; + + .action-close { + display: none; + } + } + } + + .admin__fieldset { + padding: 0; + } +} + +.advertisement-text { + line-height: @line-height__l; + height: 32rem; + + ul { + margin: 2rem 0 2rem 0; + + li { + font-size: @font-size__xs; + margin: 1.5rem 0 1.5rem 2rem; + + span { + font-size: @font-size__base; + margin-left: 2rem; + } + } + } +} + +.advertisement-modal { + .advertisement-text { + height: 35.5rem; + } +} + +.advertisement-button-next { + display: inline-block; + vertical-align: top; + float: right; +} + +.analytics-highlight { + background: url("Magento_Advertisement::images/analytics-icon.svg") no-repeat; + background-size: 65px 58px; +} + +.b2b-highlight { + background: url("Magento_Advertisement::images/b2b-icon.svg") no-repeat; + background-size: 65px 53.37px; +} + +.developer-experience-highlight { + background: url("Magento_Advertisement::images/developer-experience-icon.svg") no-repeat; + background-size: 65px 59px; +} + +.analytics-highlight, .b2b-highlight, .developer-experience-highlight { + padding: 0 0 2rem 8.5rem; + margin-left: 1rem; + + h3 { + margin: 0; + + span { + font-style: @font-style__emphasis; + font-size: @font-size__s; + font-weight: @font-weight__light; + } + } +} + +.analytics-subscription-modal { + h1:first-of-type { + background: url("Magento_Advertisement::images/analytics-icon.svg") no-repeat; + background-size: 55px 49.08px; + padding: 1.5rem 0 2rem 7rem; + } +} + +.b2b-modal { + h1:first-of-type { + background: url("Magento_Advertisement::images/b2b-icon.svg") no-repeat; + background-size: 55px 49.92px; + padding: 1.5rem 0 2rem 7rem; + } +} + +.developer-experience-modal { + h1:first-of-type { + background: url("Magento_Advertisement::images/developer-experience-icon.svg") no-repeat; + background-size: 55px 46px; + padding: 1.5rem 0 2rem 7rem; + } +} diff --git a/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/images/analytics-icon.svg b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/images/analytics-icon.svg new file mode 100644 index 0000000000000..fde91d775d444 --- /dev/null +++ b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/images/analytics-icon.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/images/b2b-icon.svg b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/images/b2b-icon.svg new file mode 100644 index 0000000000000..20552d6178c25 --- /dev/null +++ b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/images/b2b-icon.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/images/developer-experience-icon.svg b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/images/developer-experience-icon.svg new file mode 100644 index 0000000000000..50d208118aedf --- /dev/null +++ b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/images/developer-experience-icon.svg @@ -0,0 +1,28 @@ + + + + + + + + From 1c9599f8e99301e5b73b985241598dedd4e30788 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Thu, 12 Oct 2017 17:04:14 -0500 Subject: [PATCH 046/194] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- .../Model/Condition/CanViewNotification.php | 3 +- .../layout/adminhtml_dashboard_index.xml | 9 - .../advertisement_notification.xml | 264 +++++++++++++++++- 3 files changed, 264 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php b/app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php index e85ec3a3fce20..1bd28ce95e0a3 100644 --- a/app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php @@ -58,8 +58,7 @@ public function isVisible(array $arguments) return false; } - //return $this->advertisementFlagManager->setNotifiedUser($userId); - return true; + return $this->advertisementFlagManager->setNotifiedUser($userId); } /** diff --git a/app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index.xml b/app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index.xml index bf8f45cd1f898..81b87eec88a1f 100644 --- a/app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index.xml +++ b/app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index.xml @@ -9,15 +9,6 @@ xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> - - - - - - - - - diff --git a/app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml b/app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml index b1a2e3b1f709a..98d94eaef6ef0 100644 --- a/app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml +++ b/app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml @@ -96,7 +96,183 @@ ns = ${ $.ns }, index = advertisement_modal - actionCancel + closeModal + + + ns = ${ $.ns }, index = analytics_modal + openModal + + + + + + true + <![CDATA[Next >]]> + + + + + + + + actionCancel + + + + + + + + + +
+ + + + + + + advertisement-text + Advanced Reporting + provides you with a dynamic suite of reports with rich insights about the health of your + business.


As part of the Advanced Reporting service, we may also use your customer + data for such purposes as benchmarking, improving our products and services, and providing you + with new and improved analytics.


By using Magento 2.2, you agree to the Advanced + Reporting Privacy Policy + and Terms + of Service. You may opt out at any time from the Stores Configuration page.

]]> +
+
+
+
+ + + + + + + + + +
+
+ + + actionCancel + + + + + + + + + +
+ + + + + + + advertisement-text + Magento's 2.2.2 release offers a set of improvements that were developed using increased + quality standards. The release includes these features, among others: +

+
    +
  • GitHub Community Moderator Team
  • +
  • GitHub Community Videos
  • +
  • DevDocs Enhancements
  • +
+

Find the 2.2.2 details and future plans in the + Magento DevBlog. +

]]> +
+
+
+
+ + + + + + + +
+ + + actionCancel + + + + + + + + + +
+ + + + + + + advertisement-text + Magento Commerce 2.2.2 offers rich new functionality that empowers B2B merchants to transform + their online purchasing experience to achieve greater operational efficiency, improved customer + service, and sales growth. New capabilities include: +

+
    +
  • Company accounts with multiple tiers of buyers
  • +
  • Buyer roles and permissions
  • +
  • Custom catalogs and pricing
  • +
  • Quoting support
  • +
  • Rapid reorder experience
  • +
  • Payments on credit
  • +
]]> +
+
+
+
+ + + + + + + + + +
+
From 72c6debb03de2565cf5fba362b0f03ae14331d66 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Thu, 12 Oct 2017 17:09:51 -0500 Subject: [PATCH 047/194] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- .../layout/adminhtml_dashboard_index_test.xml | 80 ------------ .../ui_component/analytics_notification.xml | 116 ----------------- .../ui_component/b2b_notification.xml | 122 ------------------ .../developer_experience_notification.xml | 120 ----------------- 4 files changed, 438 deletions(-) delete mode 100644 app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index_test.xml delete mode 100644 app/code/Magento/Advertisement/view/adminhtml/ui_component/analytics_notification.xml delete mode 100644 app/code/Magento/Advertisement/view/adminhtml/ui_component/b2b_notification.xml delete mode 100644 app/code/Magento/Advertisement/view/adminhtml/ui_component/developer_experience_notification.xml diff --git a/app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index_test.xml b/app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index_test.xml deleted file mode 100644 index 72c562752516c..0000000000000 --- a/app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index_test.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - false - - 3333 - true - fieldset - advertisement_notification.advertisement_notification - advertisement_modal - advertisement-steps-wizard - data - - - - - - advertisement_notification.advertisement_notification - advertisement_modal - data - - - - - - advertisement_notification.advertisement_notification - advertisement_modal - product_attributes_listing.product_attributes_listing.product_attributes_columns.ids - advertisement_notification.advertisement_notification_data_source - data - - - - - - - - advertisement_notification.advertisement_notification - advertisement_modal - data - - - - - - - - advertisement_notification.advertisement_notification - advertisement_modal - data - - - - - - - - advertisement_notification.advertisement_notification - advertisement_modal - data - - - - - - - - - diff --git a/app/code/Magento/Advertisement/view/adminhtml/ui_component/analytics_notification.xml b/app/code/Magento/Advertisement/view/adminhtml/ui_component/analytics_notification.xml deleted file mode 100644 index 267ed8ac665e1..0000000000000 --- a/app/code/Magento/Advertisement/view/adminhtml/ui_component/analytics_notification.xml +++ /dev/null @@ -1,116 +0,0 @@ - - -
- - - advertisement_notification.advertisement_notification_data_source - - Analytics Subscription - templates/form/collapsible - - - advertisement_notification - true - simple - data - - advertisement_notification.advertisement_notification_data_source - - - - - - Magento_Ui/js/form/provider - - - - - - false - - - - - - - actionCancel - true - - - - - - - - - -
- - - - - - - advertisement-text - Advanced Reporting - provides you with a dynamic suite of reports with rich insights about the health of your - business.


As part of the Advanced Reporting service, we may also use your customer - data for such purposes as benchmarking, improving our products and services, and providing you - with new and improved analytics.


By using Magento 2.2, you agree to the Advanced - Reporting Privacy Policy - and Terms - of Service. You may opt out at any time from the Stores Configuration page.

]]> -
-
-
-
- - - - - - - - - -
-
-
diff --git a/app/code/Magento/Advertisement/view/adminhtml/ui_component/b2b_notification.xml b/app/code/Magento/Advertisement/view/adminhtml/ui_component/b2b_notification.xml deleted file mode 100644 index 0cd28487b1063..0000000000000 --- a/app/code/Magento/Advertisement/view/adminhtml/ui_component/b2b_notification.xml +++ /dev/null @@ -1,122 +0,0 @@ - - -
- - - advertisement_notification.advertisement_notification_data_source - - Analytics Subscription - templates/form/collapsible - - - advertisement_notification - true - simple - data - - advertisement_notification.advertisement_notification_data_source - - - - - - Magento_Ui/js/form/provider - - - - - - false - - - - - - - actionCancel - true - - - - - - - - - -
- - - - - - - advertisement-text - Magento Commerce 2.2.2 offers rich new functionality that empowers B2B merchants to transform - their online purchasing experience to achieve greater operational efficiency, improved customer - service, and sales growth. New capabilities include: -

-
    -
  • Company accounts with multiple tiers of buyers
  • -
  • Buyer roles and permissions
  • -
  • Custom catalogs and pricing
  • -
  • Quoting support
  • -
  • Rapid reorder experience
  • -
  • Payments on credit
  • -
]]> -
-
-
-
- - - - - - - - - -
-
-
diff --git a/app/code/Magento/Advertisement/view/adminhtml/ui_component/developer_experience_notification.xml b/app/code/Magento/Advertisement/view/adminhtml/ui_component/developer_experience_notification.xml deleted file mode 100644 index 39ce179fe7255..0000000000000 --- a/app/code/Magento/Advertisement/view/adminhtml/ui_component/developer_experience_notification.xml +++ /dev/null @@ -1,120 +0,0 @@ - - -
- - - advertisement_notification.advertisement_notification_data_source - - Analytics Subscription - templates/form/collapsible - - - advertisement_notification - true - simple - data - - advertisement_notification.advertisement_notification_data_source - - - - - - Magento_Ui/js/form/provider - - - - - - false - - - - - - - actionCancel - true - - - - - - - - - -
- - - - - - - advertisement-text - Magento's 2.2.2 release offers a set of improvements that were developed using increased - quality standards. The release includes these features, among others: -

-
    -
  • GitHub Community Moderator Team
  • -
  • GitHub Community Videos
  • -
  • DevDocs Enhancements
  • -
-

Find the 2.2.2 details and future plans in the - Magento DevBlog. -

]]> -
-
-
-
- - - - - - - - - -
-
-
From 6862db093f0fa415ff15625924f3b56acd9ad9bf Mon Sep 17 00:00:00 2001 From: crissanclick Date: Fri, 13 Oct 2017 00:12:21 +0200 Subject: [PATCH 048/194] Clean config cache --- .../Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php | 4 ++-- .../Controller/Adminhtml/Tax/IgnoreTaxNotificationTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php b/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php index 847f1312e8caf..90f1a0944bd05 100644 --- a/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php +++ b/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php @@ -51,8 +51,8 @@ public function execute() } // clear the block html cache - $this->_cacheTypeList->cleanType('block_html'); - $this->_eventManager->dispatch('adminhtml_cache_refresh_type', ['type' => 'block_html']); + $this->_cacheTypeList->cleanType('config') + $this->_eventManager->dispatch('adminhtml_cache_refresh_type', ['type' => 'config']); /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); diff --git a/app/code/Magento/Tax/Test/Unit/Controller/Adminhtml/Tax/IgnoreTaxNotificationTest.php b/app/code/Magento/Tax/Test/Unit/Controller/Adminhtml/Tax/IgnoreTaxNotificationTest.php index 0f879a6e162f5..2035885f05e8f 100644 --- a/app/code/Magento/Tax/Test/Unit/Controller/Adminhtml/Tax/IgnoreTaxNotificationTest.php +++ b/app/code/Magento/Tax/Test/Unit/Controller/Adminhtml/Tax/IgnoreTaxNotificationTest.php @@ -19,7 +19,7 @@ public function testExecute() ->getMock(); $cacheTypeList->expects($this->once()) ->method('cleanType') - ->with('block_html') + ->with('config') ->willReturn(null); $request = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) From 4c698c21d2f42acbfc35d84356ed27ff2821d45e Mon Sep 17 00:00:00 2001 From: crissanclick Date: Fri, 13 Oct 2017 00:12:53 +0200 Subject: [PATCH 049/194] Clean config cache --- .../Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php b/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php index 90f1a0944bd05..b623b6c6868e7 100644 --- a/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php +++ b/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php @@ -51,7 +51,7 @@ public function execute() } // clear the block html cache - $this->_cacheTypeList->cleanType('config') + $this->_cacheTypeList->cleanType('config'); $this->_eventManager->dispatch('adminhtml_cache_refresh_type', ['type' => 'config']); /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ From 4bf38e99db52ccdfe96d70bc6be424406f164b6d Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Thu, 12 Oct 2017 19:13:35 -0500 Subject: [PATCH 050/194] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- .../Model/Condition/CanViewNotification.php | 20 ++++++++++++-- .../Condition/CanViewNotificationTest.php | 26 +++++++++++++++---- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php index 9f1e48fb2c8f7..1f4867d692693 100644 --- a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -6,6 +6,7 @@ namespace Magento\Analytics\Model\Condition; use Magento\Backend\Model\Auth\Session; +use Magento\Framework\App\ProductMetadataInterface; use Magento\Framework\View\Layout\Condition\VisibilityConditionInterface; use Magento\Analytics\Model\NotificationFlagManager; @@ -22,6 +23,11 @@ class CanViewNotification implements VisibilityConditionInterface */ const NAME = 'can_view_notification'; + /** + * Magento Version to only show Advertisement module notification content and hide Analytics notification + */ + const VERSION_TO_HIDE = '2.2.1-dev'; + /** * @var NotificationFlagManager */ @@ -32,18 +38,26 @@ class CanViewNotification implements VisibilityConditionInterface */ private $session; + /** + * @var ProductMetadataInterface + */ + private $productMetadataInterface; + /** * CanViewNotification constructor. * * @param NotificationFlagManager $notificationFlagManager * @param Session $session + * @param ProductMetadataInterface $productMetadataInterface */ public function __construct( NotificationFlagManager $notificationFlagManager, - Session $session + Session $session, + ProductMetadataInterface $productMetadataInterface ) { $this->notificationFlagManager = $notificationFlagManager; $this->session = $session; + $this->productMetadataInterface = $productMetadataInterface; } /** @@ -53,8 +67,10 @@ public function __construct( */ public function isVisible(array $arguments) { + $version = $this->productMetadataInterface->getVersion(); + $userId = $this->session->getUser()->getId(); - if ($this->notificationFlagManager->isUserNotified($userId)) { + if (!strcmp($version, self::VERSION_TO_HIDE) || $this->notificationFlagManager->isUserNotified($userId)) { return false; } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index c0941a5a94e9e..336e4da6d5b88 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -7,6 +7,7 @@ namespace Magento\Analytics\Test\Unit\Model\Condition; use Magento\Analytics\Model\Condition\CanViewNotification; +use Magento\Framework\App\ProductMetadataInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Analytics\Model\NotificationFlagManager; use Magento\Backend\Model\Auth\Session; @@ -31,6 +32,11 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase */ private $sessionMock; + /** + * @var ProductMetadataInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $productMetadataInterfaceMock; + public function setUp() { $this->notificationFlagManagerMock = $this->getMockBuilder(NotificationFlagManager::class) @@ -40,12 +46,16 @@ public function setUp() ->disableOriginalConstructor() ->setMethods(['getUser', 'getId']) ->getMock(); + $this->productMetadataInterfaceMock = $this->getMockBuilder(ProductMetadataInterface::class) + ->disableOriginalConstructor() + ->getMock(); $objectManager = new ObjectManager($this); $this->canViewNotification = $objectManager->getObject( CanViewNotification::class, [ 'notificationFlagManager' => $this->notificationFlagManagerMock, - 'session' => $this->sessionMock + 'session' => $this->sessionMock, + 'productMetadataInterface' => $this->productMetadataInterfaceMock ] ); } @@ -53,26 +63,32 @@ public function setUp() public function isVisibleProvider() { return [ - [1, false, true], - [1, true, false] + [1, "2.2.1", false, true], + [1, "2.2.1-dev", true, false], + [1, "2.2.1", true, false], + [1, "2.2.1-dev", false, false] ]; } /** * @dataProvider isVisibleProvider * @param int $userId + * @param string $version * @param bool $isUserNotified * @param bool $expected */ - public function testIsVisible($userId, $isUserNotified, $expected) + public function testIsVisible($userId, $version, $isUserNotified, $expected) { + $this->productMetadataInterfaceMock->expects($this->once()) + ->method('getVersion') + ->willReturn($version); $this->sessionMock->expects($this->once()) ->method('getUser') ->willReturnSelf(); $this->sessionMock->expects($this->once()) ->method('getId') ->willReturn($userId); - $this->notificationFlagManagerMock->expects($this->once()) + $this->notificationFlagManagerMock->expects($this->any()) ->method('isUserNotified') ->willReturn($isUserNotified); $this->notificationFlagManagerMock->expects($this->any()) From 720496ccfa3baedb8e0435df442bc32de19b2bcc Mon Sep 17 00:00:00 2001 From: Denis Ristic Date: Fri, 13 Oct 2017 12:34:15 +0200 Subject: [PATCH 051/194] Magento setup:install interactive shell --- .../Setup/Console/Command/InstallCommand.php | 111 +++++++++++++++++- 1 file changed, 106 insertions(+), 5 deletions(-) diff --git a/setup/src/Magento/Setup/Console/Command/InstallCommand.php b/setup/src/Magento/Setup/Console/Command/InstallCommand.php index b0ccbba8c296f..98423c26d39e2 100644 --- a/setup/src/Magento/Setup/Console/Command/InstallCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InstallCommand.php @@ -13,6 +13,9 @@ use Magento\Framework\Setup\ConsoleLogger; use Symfony\Component\Console\Input\InputOption; use Magento\Setup\Model\ConfigModel; +use Symfony\Component\Console\Question\Question; +use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Helper\QuestionHelper; /** * Command to install Magento application @@ -35,6 +38,16 @@ class InstallCommand extends AbstractSetupCommand */ const INPUT_KEY_USE_SAMPLE_DATA = 'use-sample-data'; + /** + * Parameter indicating command for interactive setup + */ + const INPUT_KEY_INTERACTIVE_SETUP = 'interactive'; + + /** + * Parameter indicating command shortcut for interactive setup + */ + const INPUT_KEY_INTERACTIVE_SETUP_SHORTCUT = 'i'; + /** * Regex for sales_order_increment_prefix validation. */ @@ -109,7 +122,13 @@ protected function configure() null, InputOption::VALUE_NONE, 'Use sample data' - ) + ), + new InputOption( + self::INPUT_KEY_INTERACTIVE_SETUP, + self::INPUT_KEY_INTERACTIVE_SETUP_SHORTCUT, + InputOption::VALUE_NONE, + 'Interactive Magento instalation' + ), ]); $this->setName('setup:install') ->setDescription('Installs the Magento application') @@ -139,12 +158,17 @@ protected function initialize(InputInterface $input, OutputInterface $output) { $inputOptions = $input->getOptions(); - $configOptionsToValidate = []; - foreach ($this->configModel->getAvailableOptions() as $option) { - if (array_key_exists($option->getName(), $inputOptions)) { - $configOptionsToValidate[$option->getName()] = $inputOptions[$option->getName()]; + if ($inputOptions['interactive']) { + $configOptionsToValidate = $this->interactiveQuestions($input, $output); + } else { + $configOptionsToValidate = []; + foreach ($this->configModel->getAvailableOptions() as $option) { + if (array_key_exists($option->getName(), $inputOptions)) { + $configOptionsToValidate[$option->getName()] = $inputOptions[$option->getName()]; + } } } + $errors = $this->configModel->validate($configOptionsToValidate); $errors = array_merge($errors, $this->adminUser->validate($input)); $errors = array_merge($errors, $this->validate($input)); @@ -177,4 +201,81 @@ public function validate(InputInterface $input) } return $errors; } + + /** + * Runs interactive questions + * + * It will ask users for interactive questionst regarding setup configuration. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return string[] Array of inputs + */ + private function interactiveQuestions(InputInterface $input, OutputInterface $output) + { + $helper = $this->getHelper('question'); + $configOptionsToValidate = []; + foreach ($this->configModel->getAvailableOptions() as $option) { + + $configOptionsToValidate[$option->getName()] = $this->askQuestion($input, $output, $helper, $option); + + /*$question = new Question($option->getDescription() . '? ', $option->getDefault()); + $configOptionsToValidate[$option->getName()] = $helper->ask($input, $output, $question); + */ + } + return $configOptionsToValidate; + } + + /** + * Runs interactive questions + * + * It will ask users for interactive questionst regarding setup configuration. + * + * @param InputInterface $input + * @param OutputInterface $output + * @param QuestionHelper $helper + * @param Magento\Framework\Setup\Option\TextConfigOption|Magento\Framework\Setup\Option\FlagConfigOption\Magento\Framework\Setup\Option\SelectConfigOption $option + * @return string[] Array of inputs + */ + private function askQuestion(InputInterface $input, OutputInterface $output, QuestionHelper $helper, $option) + { + if (get_class($option) === 'Magento\Framework\Setup\Option\SelectConfigOption') { + if ($option->isValueRequired()) { + $question = new ChoiceQuestion( + $option->getDescription() . '? ', + $option->getSelectOptions(), + $option->getDefault() + ); + } else { + $question = new ChoiceQuestion( + $option->getDescription() . ' [optional]? ', + $option->getSelectOptions(), + $option->getDefault() + ); + } + $question->setValidator(function ($answer) use ($option) { + $option->validate($option->getSelectOptions()[$answer]); + return $answer; + }); + } else { + if ($option->isValueRequired()) { + $question = new Question( + $option->getDescription() . '? ', + $option->getDefault() + ); + } else { + $question = new Question( + $option->getDescription() . ' [optional]? ', + $option->getDefault() + ); + } + $question->setValidator(function ($answer) use ($option) { + $option->validate($answer); + return $answer; + }); + } + + $value = $helper->ask($input, $output, $question); + return $value; + } } From 2fd48e6a99da3f6283cbad36a9b730b7a23cf767 Mon Sep 17 00:00:00 2001 From: David Verholen Date: Fri, 13 Oct 2017 11:15:46 +0200 Subject: [PATCH 052/194] [BUGFIX][11022] include original search criteria #fixes 11022 --- .../Magento/Catalog/Model/Product/Attribute/SetRepository.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php b/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php index ab6cdb3b464a4..44e99d4f29926 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php @@ -62,6 +62,7 @@ public function save(\Magento\Eav\Api\Data\AttributeSetInterface $attributeSet) */ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria) { + $this->searchCriteriaBuilder->setFilterGroups($searchCriteria->getFilterGroups()); $this->searchCriteriaBuilder->addFilters( [ $this->filterBuilder @@ -71,6 +72,7 @@ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCr ->create(), ] ); + $this->searchCriteriaBuilder->setSortOrders((array)$searchCriteria->getSortOrders()); $this->searchCriteriaBuilder->setCurrentPage($searchCriteria->getCurrentPage()); $this->searchCriteriaBuilder->setPageSize($searchCriteria->getPageSize()); return $this->attributeSetRepository->getList($this->searchCriteriaBuilder->create()); From 0e4dd85af64b5d9ed035da373e80d6d3fb08e1f8 Mon Sep 17 00:00:00 2001 From: Denis Ristic Date: Fri, 13 Oct 2017 13:22:45 +0200 Subject: [PATCH 053/194] ADDED user and adminUser questions Code cleanup --- .../Setup/Console/Command/InstallCommand.php | 66 ++++++++++++++----- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/setup/src/Magento/Setup/Console/Command/InstallCommand.php b/setup/src/Magento/Setup/Console/Command/InstallCommand.php index 98423c26d39e2..467e94febef39 100644 --- a/setup/src/Magento/Setup/Console/Command/InstallCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InstallCommand.php @@ -215,13 +215,33 @@ private function interactiveQuestions(InputInterface $input, OutputInterface $ou { $helper = $this->getHelper('question'); $configOptionsToValidate = []; + foreach ($this->configModel->getAvailableOptions() as $option) { + $configOptionsToValidate[$option->getName()] = $this->askQuestion( + $input, + $output, + $helper, + $option, + true + ); + } - $configOptionsToValidate[$option->getName()] = $this->askQuestion($input, $output, $helper, $option); + foreach ($this->userConfig->getOptionsList() as $option) { + $configOptionsToValidate[$option->getName()] = $this->askQuestion( + $input, + $output, + $helper, + $option + ); + } - /*$question = new Question($option->getDescription() . '? ', $option->getDefault()); - $configOptionsToValidate[$option->getName()] = $helper->ask($input, $output, $question); - */ + foreach ($this->adminUser->getOptionsList() as $option) { + $configOptionsToValidate[$option->getName()] = $this->askQuestion( + $input, + $output, + $helper, + $option + ); } return $configOptionsToValidate; } @@ -234,11 +254,17 @@ private function interactiveQuestions(InputInterface $input, OutputInterface $ou * @param InputInterface $input * @param OutputInterface $output * @param QuestionHelper $helper - * @param Magento\Framework\Setup\Option\TextConfigOption|Magento\Framework\Setup\Option\FlagConfigOption\Magento\Framework\Setup\Option\SelectConfigOption $option + * @param TextConfigOption|FlagConfigOption\SelectConfigOption $option + * @param Boolean $validateInline * @return string[] Array of inputs */ - private function askQuestion(InputInterface $input, OutputInterface $output, QuestionHelper $helper, $option) - { + private function askQuestion( + InputInterface $input, + OutputInterface $output, + QuestionHelper $helper, + $option, + $validateInline = false + ) { if (get_class($option) === 'Magento\Framework\Setup\Option\SelectConfigOption') { if ($option->isValueRequired()) { $question = new ChoiceQuestion( @@ -253,10 +279,6 @@ private function askQuestion(InputInterface $input, OutputInterface $output, Que $option->getDefault() ); } - $question->setValidator(function ($answer) use ($option) { - $option->validate($option->getSelectOptions()[$answer]); - return $answer; - }); } else { if ($option->isValueRequired()) { $question = new Question( @@ -269,13 +291,25 @@ private function askQuestion(InputInterface $input, OutputInterface $output, Que $option->getDefault() ); } - $question->setValidator(function ($answer) use ($option) { - $option->validate($answer); - return $answer; - }); + } + $question->setValidator(function ($answer) use ($option, $validateInline) { + $answer = trim($answer); + + if (get_class($option) === 'Magento\Framework\Setup\Option\SelectConfigOption') { + $answer = $option->getSelectOptions()[$answer]; + } + + if ($validateInline) { + $option->validate($answer); + } + + return $answer; + }); + $value = $helper->ask($input, $output, $question); + return $value; } -} +} \ No newline at end of file From ce12a7439fe03a690a5d5acb76dde333118c3d80 Mon Sep 17 00:00:00 2001 From: Denis Ristic Date: Fri, 13 Oct 2017 14:02:56 +0200 Subject: [PATCH 054/194] ADDED re-run command output FIXED phpcs validation --- .../Setup/Console/Command/InstallCommand.php | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/setup/src/Magento/Setup/Console/Command/InstallCommand.php b/setup/src/Magento/Setup/Console/Command/InstallCommand.php index 467e94febef39..a2e8715b02233 100644 --- a/setup/src/Magento/Setup/Console/Command/InstallCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InstallCommand.php @@ -169,6 +169,14 @@ protected function initialize(InputInterface $input, OutputInterface $output) } } + if ($inputOptions['interactive']) { + $command = ''; + foreach ($configOptionsToValidate as $key => $value) { + $command .= " --{$key}={$value}"; + } + $output->writeln("Try re-running command: php bin/magento setup:install{$command}"); + } + $errors = $this->configModel->validate($configOptionsToValidate); $errors = array_merge($errors, $this->adminUser->validate($input)); $errors = array_merge($errors, $this->validate($input)); @@ -226,6 +234,8 @@ private function interactiveQuestions(InputInterface $input, OutputInterface $ou ); } + $output->writeln(""); + foreach ($this->userConfig->getOptionsList() as $option) { $configOptionsToValidate[$option->getName()] = $this->askQuestion( $input, @@ -235,6 +245,8 @@ private function interactiveQuestions(InputInterface $input, OutputInterface $ou ); } + $output->writeln(""); + foreach ($this->adminUser->getOptionsList() as $option) { $configOptionsToValidate[$option->getName()] = $this->askQuestion( $input, @@ -243,7 +255,17 @@ private function interactiveQuestions(InputInterface $input, OutputInterface $ou $option ); } - return $configOptionsToValidate; + + $output->writeln(""); + + $returnConfigOptionsToValidate = []; + foreach ($configOptionsToValidate as $key => $value) { + if ($value != '') { + $returnConfigOptionsToValidate[$key] = $value; + } + } + + return $returnConfigOptionsToValidate; } /** @@ -265,7 +287,7 @@ private function askQuestion( $option, $validateInline = false ) { - if (get_class($option) === 'Magento\Framework\Setup\Option\SelectConfigOption') { + if ($option instanceof \Magento\Framework\Setup\Option\SelectConfigOption) { if ($option->isValueRequired()) { $question = new ChoiceQuestion( $option->getDescription() . '? ', @@ -291,16 +313,20 @@ private function askQuestion( $option->getDefault() ); } - } $question->setValidator(function ($answer) use ($option, $validateInline) { - $answer = trim($answer); - if (get_class($option) === 'Magento\Framework\Setup\Option\SelectConfigOption') { + if ($option instanceof \Magento\Framework\Setup\Option\SelectConfigOption) { $answer = $option->getSelectOptions()[$answer]; } + if ($answer == null) { + $answer = ''; + } else { + $answer = trim($answer); + } + if ($validateInline) { $option->validate($answer); } @@ -312,4 +338,4 @@ private function askQuestion( return $value; } -} \ No newline at end of file +} From a85d164f6c08b1fc37fd4df1fbd3c4a8e871749d Mon Sep 17 00:00:00 2001 From: David Verholen Date: Fri, 13 Oct 2017 15:17:23 +0200 Subject: [PATCH 055/194] [BUGFIX][11022] return original search criteria in search result --- .../Model/Product/Attribute/SetRepository.php | 7 ++++++- .../Catalog/Api/AttributeSetRepositoryTest.php | 14 ++------------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php b/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php index 44e99d4f29926..dafa7581253fd 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php @@ -72,10 +72,15 @@ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCr ->create(), ] ); + $this->searchCriteriaBuilder->setSortOrders((array)$searchCriteria->getSortOrders()); $this->searchCriteriaBuilder->setCurrentPage($searchCriteria->getCurrentPage()); $this->searchCriteriaBuilder->setPageSize($searchCriteria->getPageSize()); - return $this->attributeSetRepository->getList($this->searchCriteriaBuilder->create()); + + $searchResult = $this->attributeSetRepository->getList($this->searchCriteriaBuilder->create()); + $searchResult->setSearchCriteria($searchCriteria); + + return $searchResult; } /** diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetRepositoryTest.php index 5e640390c3231..4f917a9c9961a 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetRepositoryTest.php @@ -165,19 +165,9 @@ public function testGetList() { $searchCriteria = [ 'searchCriteria' => [ - 'filter_groups' => [ - [ - 'filters' => [ - [ - 'field' => 'entity_type_code', - 'value' => 'catalog_product', - 'condition_type' => 'eq', - ], - ], - ], - ], + 'filter_groups' => [], 'current_page' => 1, - 'page_size' => 2, + 'page_size' => 2 ], ]; From 3ec56ac9158f5d344c387f62315696360a12a60d Mon Sep 17 00:00:00 2001 From: David Verholen Date: Fri, 13 Oct 2017 15:18:40 +0200 Subject: [PATCH 056/194] [BUGFIX][11022] typecast filtergroups array --- .../Magento/Catalog/Model/Product/Attribute/SetRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php b/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php index dafa7581253fd..14774103b8cd2 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php @@ -62,7 +62,7 @@ public function save(\Magento\Eav\Api\Data\AttributeSetInterface $attributeSet) */ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria) { - $this->searchCriteriaBuilder->setFilterGroups($searchCriteria->getFilterGroups()); + $this->searchCriteriaBuilder->setFilterGroups((array)$searchCriteria->getFilterGroups()); $this->searchCriteriaBuilder->addFilters( [ $this->filterBuilder From fb41335de5520b6669dde4091d63fb13d0890154 Mon Sep 17 00:00:00 2001 From: Ievgen Shakhsuvarov Date: Fri, 13 Oct 2017 16:26:23 +0300 Subject: [PATCH 057/194] magento/magento2#11363: Unmask exception message during product import - Test updated --- .../Magento/ImportExport/Model/ImportTest.php | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/dev/tests/integration/testsuite/Magento/ImportExport/Model/ImportTest.php b/dev/tests/integration/testsuite/Magento/ImportExport/Model/ImportTest.php index 5ba955430021f..332ca5fba75c7 100644 --- a/dev/tests/integration/testsuite/Magento/ImportExport/Model/ImportTest.php +++ b/dev/tests/integration/testsuite/Magento/ImportExport/Model/ImportTest.php @@ -135,6 +135,31 @@ public function testValidateSourceException() $this->_model->validateSource($source); } + public function testValidateSourceExceptionMessage() + { + $exceptionMessage = 'Test Exception Message.'; + + $validationStrategy = ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_STOP_ON_ERROR; + $this->_model->setEntity('catalog_product'); + $this->_model->setData(\Magento\ImportExport\Model\Import::FIELD_NAME_VALIDATION_STRATEGY, $validationStrategy); + $this->_model->setData(\Magento\ImportExport\Model\Import::FIELD_NAME_ALLOWED_ERROR_COUNT, 0); + + /** @var \Magento\ImportExport\Model\Import\AbstractSource|\PHPUnit_Framework_MockObject_MockObject $source */ + $source = $this->getMockForAbstractClass( + \Magento\ImportExport\Model\Import\AbstractSource::class, + [['sku', 'name']] + ); + $source->expects($this->any())->method('_getNextRow')->willThrowException( + new \Exception($exceptionMessage) + ); + + $this->assertFalse($this->_model->validateSource($source)); + $this->assertEquals( + $exceptionMessage, + $this->_model->getErrorAggregator()->getAllErrors()[0]->getErrorMessage() + ); + } + public function testGetEntity() { $entityName = 'entity_name'; From 951f0a0b6b58282fc590eb71a8996b65e806360d Mon Sep 17 00:00:00 2001 From: Joan He Date: Fri, 13 Oct 2017 11:06:18 -0500 Subject: [PATCH 058/194] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- .../Model/Condition/CanViewNotification.php | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php index 1f4867d692693..62ac77a916917 100644 --- a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -6,7 +6,7 @@ namespace Magento\Analytics\Model\Condition; use Magento\Backend\Model\Auth\Session; -use Magento\Framework\App\ProductMetadataInterface; +use Magento\Framework\Module\ModuleListInterface; use Magento\Framework\View\Layout\Condition\VisibilityConditionInterface; use Magento\Analytics\Model\NotificationFlagManager; @@ -23,11 +23,6 @@ class CanViewNotification implements VisibilityConditionInterface */ const NAME = 'can_view_notification'; - /** - * Magento Version to only show Advertisement module notification content and hide Analytics notification - */ - const VERSION_TO_HIDE = '2.2.1-dev'; - /** * @var NotificationFlagManager */ @@ -39,25 +34,24 @@ class CanViewNotification implements VisibilityConditionInterface private $session; /** - * @var ProductMetadataInterface + * @var ModuleListInterface */ - private $productMetadataInterface; + private $moduleList; /** * CanViewNotification constructor. * * @param NotificationFlagManager $notificationFlagManager * @param Session $session - * @param ProductMetadataInterface $productMetadataInterface */ public function __construct( NotificationFlagManager $notificationFlagManager, Session $session, - ProductMetadataInterface $productMetadataInterface + ModuleListInterface $moduleList ) { $this->notificationFlagManager = $notificationFlagManager; $this->session = $session; - $this->productMetadataInterface = $productMetadataInterface; + $this->moduleList = $moduleList; } /** @@ -67,10 +61,8 @@ public function __construct( */ public function isVisible(array $arguments) { - $version = $this->productMetadataInterface->getVersion(); - $userId = $this->session->getUser()->getId(); - if (!strcmp($version, self::VERSION_TO_HIDE) || $this->notificationFlagManager->isUserNotified($userId)) { + if ($this->moduleList->has('Magento_Advertisement') || $this->notificationFlagManager->isUserNotified($userId)) { return false; } From 8e843ade22f640c9626eca9ce1111bd2edef5a3b Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Fri, 13 Oct 2017 19:42:07 +0200 Subject: [PATCH 059/194] Rewrite to have one test using a dataprovider --- .../Magento/Sales/Model/Order/StatusTest.php | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php index d53ff46122f57..db3afa031b278 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php @@ -12,37 +12,38 @@ */ class StatusTest extends \PHPUnit\Framework\TestCase { - /** - * In the backend the regular label must be showed. - * - * @magentoDataFixture Magento/Sales/_files/order_status.php - */ - public function testTheLabelIsUsedInTheBackend() + public function theCorrectLabelIsUsedDependingOnTheAreaProvider() { - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $objectManager->get(\Magento\Framework\App\State::class)->setAreaCode('adminhtml'); - - /** @var \Magento\Sales\Model\Order $order */ - $order = $objectManager->create(\Magento\Sales\Model\Order::class); - $order->loadByIncrementId('100000001'); - - $this->assertEquals('Example', $order->getStatusLabel()); + return [ + 'backend label' => [ + 'adminhtml', + 'Example', + ], + 'store view label' => [ + 'frontend', + 'Store view example', + ], + ]; } /** - * In the frontend the store view specific label must be showed. + * In the backend the regular label must be showed. + * + * @param $area + * @param $result * * @magentoDataFixture Magento/Sales/_files/order_status.php + * @dataProvider theCorrectLabelIsUsedDependingOnTheAreaProvider */ - public function testTheStoreViewLabelIsUsedInTheFrontend() + public function testTheCorrectLabelIsUsedDependingOnTheArea($area, $result) { $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $objectManager->get(\Magento\Framework\App\State::class)->setAreaCode('frontend'); + $objectManager->get(\Magento\Framework\App\State::class)->setAreaCode('adminhtml'); /** @var \Magento\Sales\Model\Order $order */ $order = $objectManager->create(\Magento\Sales\Model\Order::class); $order->loadByIncrementId('100000001'); - $this->assertEquals('Store view example', $order->getStatusLabel()); + $this->assertEquals('Example', $order->getStatusLabel()); } } From 80ed8330926834840848330dc55f40b41b740bd5 Mon Sep 17 00:00:00 2001 From: peterjaap Date: Sat, 14 Oct 2017 12:38:24 +0200 Subject: [PATCH 060/194] Added fix for issue 2991 to fetch billing and shipping addresses to enable getting a correct price through the (web) API after adding a product to an empty cart --- app/code/Magento/Quote/Model/QuoteManagement.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Quote/Model/QuoteManagement.php b/app/code/Magento/Quote/Model/QuoteManagement.php index 49206ff924f13..6089e6b670513 100644 --- a/app/code/Magento/Quote/Model/QuoteManagement.php +++ b/app/code/Magento/Quote/Model/QuoteManagement.php @@ -232,6 +232,8 @@ public function createEmptyCart() $quote->setShippingAddress($this->quoteAddressFactory->create()); try { + $quote->getBillingAddress(); + $quote->getShippingAddress()->setCollectShippingRates(true); $this->quoteRepository->save($quote); } catch (\Exception $e) { throw new CouldNotSaveException(__('Cannot create quote')); From 24d6a578c7825b491cae179c9597b0476ee282bc Mon Sep 17 00:00:00 2001 From: peterjaap Date: Sat, 14 Oct 2017 12:38:24 +0200 Subject: [PATCH 061/194] Added fix for issue 2991 to fetch billing and shipping addresses to enable getting a correct price through the (web) API after adding a product to an empty cart --- app/code/Magento/Quote/Model/QuoteManagement.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/Quote/Model/QuoteManagement.php b/app/code/Magento/Quote/Model/QuoteManagement.php index 49206ff924f13..9b88d102b733f 100644 --- a/app/code/Magento/Quote/Model/QuoteManagement.php +++ b/app/code/Magento/Quote/Model/QuoteManagement.php @@ -232,6 +232,9 @@ public function createEmptyCart() $quote->setShippingAddress($this->quoteAddressFactory->create()); try { + $quote->getBillingAddress()->setCollectShippingRates(true); + $quote->getShippingAddress()->setCollectShippingRates(true); + $this->quoteRepository->save($quote); } catch (\Exception $e) { throw new CouldNotSaveException(__('Cannot create quote')); From 69ef9dab06e1971c3db82be80778ece254a50443 Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Sat, 14 Oct 2017 13:08:37 +0200 Subject: [PATCH 062/194] Forgot to use the dataprovider variables --- .../testsuite/Magento/Sales/Model/Order/StatusTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php index db3afa031b278..e4b64e77d6e05 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php @@ -38,12 +38,12 @@ public function theCorrectLabelIsUsedDependingOnTheAreaProvider() public function testTheCorrectLabelIsUsedDependingOnTheArea($area, $result) { $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $objectManager->get(\Magento\Framework\App\State::class)->setAreaCode('adminhtml'); + $objectManager->get(\Magento\Framework\App\State::class)->setAreaCode($area); /** @var \Magento\Sales\Model\Order $order */ $order = $objectManager->create(\Magento\Sales\Model\Order::class); $order->loadByIncrementId('100000001'); - $this->assertEquals('Example', $order->getStatusLabel()); + $this->assertEquals($result, $order->getStatusLabel()); } } From 0f4b69493b125c8113b43dac72db414e223a5d51 Mon Sep 17 00:00:00 2001 From: Gabriel Queiroz Silva Date: Thu, 12 Oct 2017 14:49:18 -0300 Subject: [PATCH 063/194] Allow setting of http response status code in a Redirection --- .../Framework/Controller/Result/Redirect.php | 18 +++++-- .../Test/Unit/Result/RedirectTest.php | 52 +++++++++++++------ 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/lib/internal/Magento/Framework/Controller/Result/Redirect.php b/lib/internal/Magento/Framework/Controller/Result/Redirect.php index d68caeb3e4409..120b18d873cff 100644 --- a/lib/internal/Magento/Framework/Controller/Result/Redirect.php +++ b/lib/internal/Magento/Framework/Controller/Result/Redirect.php @@ -9,6 +9,8 @@ use Magento\Framework\App; use Magento\Framework\App\Response\HttpInterface as HttpResponseInterface; use Magento\Framework\Controller\AbstractResult; +use Magento\Framework\App\Response\RedirectInterface; +use Magento\Framework\UrlInterface; /** * In many cases controller actions may result in a redirect @@ -18,13 +20,14 @@ */ class Redirect extends AbstractResult { + /** - * @var \Magento\Framework\App\Response\RedirectInterface + * @var RedirectInterface */ protected $redirect; /** - * @var \Magento\Framework\UrlInterface + * @var UrlInterface */ protected $urlBuilder; @@ -37,11 +40,11 @@ class Redirect extends AbstractResult * Constructor * * @param App\Response\RedirectInterface $redirect - * @param \Magento\Framework\UrlInterface $urlBuilder + * @param UrlInterface $urlBuilder */ public function __construct( App\Response\RedirectInterface $redirect, - \Magento\Framework\UrlInterface $urlBuilder + UrlInterface $urlBuilder ) { $this->redirect = $redirect; $this->urlBuilder = $urlBuilder; @@ -70,6 +73,7 @@ public function setRefererOrBaseUrl() } /** + * URL Setter * @param string $url * @return $this */ @@ -97,7 +101,11 @@ public function setPath($path, array $params = []) */ protected function render(HttpResponseInterface $response) { - $response->setRedirect($this->url); + if (empty($this->httpResponseCode)) { + $response->setRedirect($this->url); + } else { + $response->setRedirect($this->url, $this->httpResponseCode); + } return $this; } } diff --git a/lib/internal/Magento/Framework/Controller/Test/Unit/Result/RedirectTest.php b/lib/internal/Magento/Framework/Controller/Test/Unit/Result/RedirectTest.php index 0295f0713d429..65e7ee489e84c 100644 --- a/lib/internal/Magento/Framework/Controller/Test/Unit/Result/RedirectTest.php +++ b/lib/internal/Magento/Framework/Controller/Test/Unit/Result/RedirectTest.php @@ -6,10 +6,13 @@ namespace Magento\Framework\Controller\Test\Unit\Result; -use Magento\Framework\App\Response\HttpInterface as HttpResponseInterface; +use \PHPUnit\Framework\TestCase; +use \Magento\Framework\App\Response\HttpInterface as HttpResponseInterface; +use \Magento\Framework\App\Response\RedirectInterface; use \Magento\Framework\Controller\Result\Redirect; +use \Magento\Framework\UrlInterface; -class RedirectTest extends \PHPUnit\Framework\TestCase +class RedirectTest extends TestCase { /** @var \Magento\Framework\Controller\Result\Redirect */ protected $redirect; @@ -28,9 +31,9 @@ class RedirectTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $this->redirectInterface = $this->createMock(\Magento\Framework\App\Response\RedirectInterface::class); - $this->urlBuilder = $this->createMock(\Magento\Framework\UrlInterface::class); - $this->urlInterface = $this->createMock(\Magento\Framework\UrlInterface::class); + $this->redirectInterface = $this->createMock(RedirectInterface::class); + $this->urlBuilder = $this->createMock(UrlInterface::class); + $this->urlInterface = $this->createMock(UrlInterface::class); $this->response = $this->createMock(HttpResponseInterface::class); $this->redirect = new Redirect($this->redirectInterface, $this->urlInterface); } @@ -39,7 +42,7 @@ public function testSetRefererUrl() { $this->redirectInterface->expects($this->once())->method('getRefererUrl'); $this->assertInstanceOf( - \Magento\Framework\Controller\Result\Redirect::class, + Redirect::class, $this->redirect->setRefererUrl() ); } @@ -48,7 +51,7 @@ public function testSetRefererOrBaseUrl() { $this->redirectInterface->expects($this->once())->method('getRedirectUrl'); $this->assertInstanceOf( - \Magento\Framework\Controller\Result\Redirect::class, + Redirect::class, $this->redirect->setRefererOrBaseUrl() ); } @@ -56,7 +59,7 @@ public function testSetRefererOrBaseUrl() public function testSetUrl() { $url = 'http://test.com'; - $this->assertInstanceOf(\Magento\Framework\Controller\Result\Redirect::class, $this->redirect->setUrl($url)); + $this->assertInstanceOf(Redirect::class, $this->redirect->setUrl($url)); } public function testSetPath() @@ -67,17 +70,36 @@ public function testSetPath() $this->returnValue($params) ); $this->assertInstanceOf( - \Magento\Framework\Controller\Result\Redirect::class, + Redirect::class, $this->redirect->setPath($path, $params) ); } - public function testRender() + public function httpRedirectResponseStatusCodes() { - $this->response->expects($this->once())->method('setRedirect'); - $this->assertInstanceOf( - \Magento\Framework\Controller\Result\Redirect::class, - $this->redirect->renderResult($this->response) - ); + return [ + [302, null], + [302, 302], + [303, 303] + ]; + } + + /** + * @param int $expectedStatusCode + * @param int|null $actualStatusCode + * @dataProvider httpRedirectResponseStatusCodes + */ + public function testRender($expectedStatusCode, $actualStatusCode) + { + $url = 'http://test.com'; + $this->redirect->setUrl($url); + $this->redirect->setHttpResponseCode($actualStatusCode); + + $this->response + ->expects($this->once()) + ->method('setRedirect') + ->with($url, $expectedStatusCode); + + $this->redirect->renderResult($this->response); } } From 14371f2c49710552d829f2752689a161650ad2ef Mon Sep 17 00:00:00 2001 From: Joan He Date: Sat, 14 Oct 2017 15:13:11 -0500 Subject: [PATCH 064/194] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 - fix modal enters from top of the window --- .../web/css/source/_module.less | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less index b6b3a635ae2cb..4689e8352e222 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less @@ -112,3 +112,26 @@ padding: 1.5rem 0 2rem 7rem; } } + +.lib-modal-popup() { + -webkit-transition: visibility 0s .5s, opacity .5s ease; + transition: visibility 0s .5s, opacity .5s ease; + + &._show { + visibility: visible; + opacity: 1; + -webkit-transition: opacity .5s ease; + transition: opacity .5s ease; + } + + .modal-inner-wrap { + -webkit-transform: translateX(0); + transform: translateX(0); + -webkit-transition: -webkit-transform 0s; + transition: transform 0s; + .lib-css(background-color, @modal__background-color); + .lib-css(box-shadow, @modal__box-shadow); + opacity: 1; + pointer-events: auto; + } +} \ No newline at end of file From 846f117afded21fdea34fc0b11fc395f65d2da78 Mon Sep 17 00:00:00 2001 From: peterjaap Date: Sun, 15 Oct 2017 10:39:21 +0200 Subject: [PATCH 065/194] Removed setCollectShippingRates() on ShippingAddress because that method does not exist for a billing address. Also removed getBillingAddress() call because the empty address is already created 3 lines above. --- app/code/Magento/Quote/Model/QuoteManagement.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Quote/Model/QuoteManagement.php b/app/code/Magento/Quote/Model/QuoteManagement.php index 9b88d102b733f..72c1942159016 100644 --- a/app/code/Magento/Quote/Model/QuoteManagement.php +++ b/app/code/Magento/Quote/Model/QuoteManagement.php @@ -232,7 +232,6 @@ public function createEmptyCart() $quote->setShippingAddress($this->quoteAddressFactory->create()); try { - $quote->getBillingAddress()->setCollectShippingRates(true); $quote->getShippingAddress()->setCollectShippingRates(true); $this->quoteRepository->save($quote); From cefb25a91d060f61074919b95c7909a8618fe134 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Tue, 17 Oct 2017 15:16:15 -0500 Subject: [PATCH 066/194] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- .../Model/Condition/CanViewNotification.php | 4 ++- .../Condition/CanViewNotificationTest.php | 32 +++++++++---------- .../web/css/source/_module.less | 17 +++++----- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php index 62ac77a916917..7ec0cd3cefc08 100644 --- a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -43,6 +43,7 @@ class CanViewNotification implements VisibilityConditionInterface * * @param NotificationFlagManager $notificationFlagManager * @param Session $session + * @param ModuleListInterface $moduleList */ public function __construct( NotificationFlagManager $notificationFlagManager, @@ -62,7 +63,8 @@ public function __construct( public function isVisible(array $arguments) { $userId = $this->session->getUser()->getId(); - if ($this->moduleList->has('Magento_Advertisement') || $this->notificationFlagManager->isUserNotified($userId)) { + if ($this->moduleList->has('Magento_Advertisement') + || $this->notificationFlagManager->isUserNotified($userId)) { return false; } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index 336e4da6d5b88..ba45d5a3eb0da 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -7,10 +7,10 @@ namespace Magento\Analytics\Test\Unit\Model\Condition; use Magento\Analytics\Model\Condition\CanViewNotification; -use Magento\Framework\App\ProductMetadataInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Analytics\Model\NotificationFlagManager; use Magento\Backend\Model\Auth\Session; +use Magento\Framework\Module\ModuleListInterface; /** * Class CanViewNotificationTest @@ -33,21 +33,21 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase private $sessionMock; /** - * @var ProductMetadataInterface|\PHPUnit_Framework_MockObject_MockObject + * @var ModuleListInterface|\PHPUnit_Framework_MockObject_MockObject */ - private $productMetadataInterfaceMock; + private $moduleListMock; public function setUp() { $this->notificationFlagManagerMock = $this->getMockBuilder(NotificationFlagManager::class) ->disableOriginalConstructor() ->getMock(); - $this->sessionMock = $this->getMockBuilder(Session::class) + $this->moduleListMock = $this->getMockBuilder(ModuleListInterface::class) ->disableOriginalConstructor() - ->setMethods(['getUser', 'getId']) ->getMock(); - $this->productMetadataInterfaceMock = $this->getMockBuilder(ProductMetadataInterface::class) + $this->sessionMock = $this->getMockBuilder(Session::class) ->disableOriginalConstructor() + ->setMethods(['getUser', 'getId']) ->getMock(); $objectManager = new ObjectManager($this); $this->canViewNotification = $objectManager->getObject( @@ -55,7 +55,7 @@ public function setUp() [ 'notificationFlagManager' => $this->notificationFlagManagerMock, 'session' => $this->sessionMock, - 'productMetadataInterface' => $this->productMetadataInterfaceMock + 'moduleList' => $this->moduleListMock ] ); } @@ -63,28 +63,28 @@ public function setUp() public function isVisibleProvider() { return [ - [1, "2.2.1", false, true], - [1, "2.2.1-dev", true, false], - [1, "2.2.1", true, false], - [1, "2.2.1-dev", false, false] + [1, false, false, true], // No Ad Module, Has not seen before, should see popup + [1, true, false, false], // Has Ad Module, Has not seen before, should not see popup + [1, false, true, false], // No Ad Module, Has seen before, should not see popup + [1, true, true, false] // Has Ad Module, Has seen before, should not see popup ]; } /** * @dataProvider isVisibleProvider * @param int $userId - * @param string $version + * @param bool $hasNotificationModule * @param bool $isUserNotified * @param bool $expected */ - public function testIsVisible($userId, $version, $isUserNotified, $expected) + public function testIsVisible($userId, $hasNotificationModule, $isUserNotified, $expected) { - $this->productMetadataInterfaceMock->expects($this->once()) - ->method('getVersion') - ->willReturn($version); $this->sessionMock->expects($this->once()) ->method('getUser') ->willReturnSelf(); + $this->moduleListMock->expects($this->once()) + ->method('has') + ->willReturn($hasNotificationModule); $this->sessionMock->expects($this->once()) ->method('getId') ->willReturn($userId); diff --git a/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less index 4689e8352e222..49e0e17a2cb0d 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less @@ -30,7 +30,6 @@ .advertisement-text { line-height: @line-height__l; - height: 32rem; ul { margin: 2rem 0 2rem 0; @@ -47,16 +46,16 @@ } } -.advertisement-modal { - .advertisement-text { - height: 35.5rem; - } -} - -.advertisement-button-next { +.advertisement-button-next, .advertisement-button-back { display: inline-block; vertical-align: top; float: right; + position: absolute; + bottom: 4rem; +} + +.advertisement-button-next { + right: 4rem; } .analytics-highlight { @@ -134,4 +133,4 @@ opacity: 1; pointer-events: auto; } -} \ No newline at end of file +} From 58f37f7b4d95ed0ea3097d5dc167ab86ad625d26 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Tue, 17 Oct 2017 15:18:38 -0500 Subject: [PATCH 067/194] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- .../Test/Unit/Model/Condition/CanViewNotificationTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index ba45d5a3eb0da..0af3ae1ff21e2 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -63,10 +63,10 @@ public function setUp() public function isVisibleProvider() { return [ - [1, false, false, true], // No Ad Module, Has not seen before, should see popup - [1, true, false, false], // Has Ad Module, Has not seen before, should not see popup - [1, false, true, false], // No Ad Module, Has seen before, should not see popup - [1, true, true, false] // Has Ad Module, Has seen before, should not see popup + [1, false, false, true], + [1, true, false, false], + [1, false, true, false], + [1, true, true, false] ]; } From c2f3a9bfea102f2900991e5b544b3b10b6f16d65 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Tue, 17 Oct 2017 15:23:54 -0500 Subject: [PATCH 068/194] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- .../Unit/Model/Condition/CanViewNotificationTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index 0af3ae1ff21e2..ccf3f1efa599b 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -42,13 +42,13 @@ public function setUp() $this->notificationFlagManagerMock = $this->getMockBuilder(NotificationFlagManager::class) ->disableOriginalConstructor() ->getMock(); - $this->moduleListMock = $this->getMockBuilder(ModuleListInterface::class) - ->disableOriginalConstructor() - ->getMock(); $this->sessionMock = $this->getMockBuilder(Session::class) ->disableOriginalConstructor() ->setMethods(['getUser', 'getId']) ->getMock(); + $this->moduleListMock = $this->getMockBuilder(ModuleListInterface::class) + ->disableOriginalConstructor() + ->getMock(); $objectManager = new ObjectManager($this); $this->canViewNotification = $objectManager->getObject( CanViewNotification::class, @@ -82,12 +82,12 @@ public function testIsVisible($userId, $hasNotificationModule, $isUserNotified, $this->sessionMock->expects($this->once()) ->method('getUser') ->willReturnSelf(); - $this->moduleListMock->expects($this->once()) - ->method('has') - ->willReturn($hasNotificationModule); $this->sessionMock->expects($this->once()) ->method('getId') ->willReturn($userId); + $this->moduleListMock->expects($this->once()) + ->method('has') + ->willReturn($hasNotificationModule); $this->notificationFlagManagerMock->expects($this->any()) ->method('isUserNotified') ->willReturn($isUserNotified); From 00c922a076640407941ae9fd4b13d5af4457d1a0 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 18 Oct 2017 09:50:47 -0500 Subject: [PATCH 069/194] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- .../{DummyDataProvider.php => DataProvider.php} | 8 ++++---- app/code/Magento/Advertisement/composer.json | 1 - app/code/Magento/Advertisement/etc/module.xml | 1 - .../adminhtml/ui_component/advertisement_notification.xml | 2 +- composer.json | 1 + 5 files changed, 6 insertions(+), 7 deletions(-) rename app/code/Magento/Advertisement/Ui/DataProvider/{DummyDataProvider.php => DataProvider.php} (95%) diff --git a/app/code/Magento/Advertisement/Ui/DataProvider/DummyDataProvider.php b/app/code/Magento/Advertisement/Ui/DataProvider/DataProvider.php similarity index 95% rename from app/code/Magento/Advertisement/Ui/DataProvider/DummyDataProvider.php rename to app/code/Magento/Advertisement/Ui/DataProvider/DataProvider.php index 7af053190645a..60d374dd6606c 100644 --- a/app/code/Magento/Advertisement/Ui/DataProvider/DummyDataProvider.php +++ b/app/code/Magento/Advertisement/Ui/DataProvider/DataProvider.php @@ -11,9 +11,9 @@ use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface; /** - * Class which serves as stub for degenerated UI component. + * Data Provider for the Advertisement Notification UI component. */ -class DummyDataProvider implements DataProviderInterface +class DataProvider implements DataProviderInterface { /** * Search result object. @@ -156,7 +156,7 @@ public function getFieldsMetaInfo($fieldSetName) */ public function getPrimaryFieldName() { - return ''; + return 'advertisement_notification'; } /** @@ -166,7 +166,7 @@ public function getPrimaryFieldName() */ public function getRequestFieldName() { - return ''; + return 'advertisement_notification'; } /** diff --git a/app/code/Magento/Advertisement/composer.json b/app/code/Magento/Advertisement/composer.json index 93660553a3cff..f878bf9f91098 100644 --- a/app/code/Magento/Advertisement/composer.json +++ b/app/code/Magento/Advertisement/composer.json @@ -4,7 +4,6 @@ "require": { "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", "magento/module-backend": "100.2.*", - "magento/module-store": "100.2.*", "magento/framework": "100.2.*" }, "type": "magento2-module", diff --git a/app/code/Magento/Advertisement/etc/module.xml b/app/code/Magento/Advertisement/etc/module.xml index 119951fcc66a8..5db6c24c13cb6 100644 --- a/app/code/Magento/Advertisement/etc/module.xml +++ b/app/code/Magento/Advertisement/etc/module.xml @@ -9,7 +9,6 @@ - diff --git a/app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml b/app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml index 98d94eaef6ef0..cb57f3d7eadb6 100644 --- a/app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml +++ b/app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml @@ -28,7 +28,7 @@ Magento_Ui/js/form/provider - + false diff --git a/composer.json b/composer.json index ca0e2b7f7f681..37e9c3d481d81 100644 --- a/composer.json +++ b/composer.json @@ -85,6 +85,7 @@ "magento/module-marketplace": "100.2.0", "magento/module-admin-notification": "100.2.0", "magento/module-advanced-pricing-import-export": "100.2.0", + "magento/module-advertisement": "100.2.0-dev", "magento/module-analytics": "100.2.0-dev", "magento/module-authorization": "100.2.0", "magento/module-authorizenet": "100.2.0", From 0f682c5f1dca5142b32e9b887b4e6dda192e5f80 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 18 Oct 2017 11:16:27 -0500 Subject: [PATCH 070/194] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- app/code/Magento/Advertisement/composer.json | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Advertisement/composer.json b/app/code/Magento/Advertisement/composer.json index f878bf9f91098..307b862a0b649 100644 --- a/app/code/Magento/Advertisement/composer.json +++ b/app/code/Magento/Advertisement/composer.json @@ -7,7 +7,7 @@ "magento/framework": "100.2.*" }, "type": "magento2-module", - "version": "100.2.0-dev", + "version": "100.2.0", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/composer.json b/composer.json index 37e9c3d481d81..b4104c3a4f046 100644 --- a/composer.json +++ b/composer.json @@ -85,7 +85,7 @@ "magento/module-marketplace": "100.2.0", "magento/module-admin-notification": "100.2.0", "magento/module-advanced-pricing-import-export": "100.2.0", - "magento/module-advertisement": "100.2.0-dev", + "magento/module-advertisement": "100.2.0", "magento/module-analytics": "100.2.0-dev", "magento/module-authorization": "100.2.0", "magento/module-authorizenet": "100.2.0", From 7b7c78126b3ed70173aca807b4c14b5799f6a19d Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 18 Oct 2017 11:35:38 -0500 Subject: [PATCH 071/194] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- composer.lock | 352 +++++++++++++++++++++++++------------------------- 1 file changed, 177 insertions(+), 175 deletions(-) diff --git a/composer.lock b/composer.lock index 52d00b3c5f544..11affe4e33322 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "0b1cc5912e2f422e953f6c4730434184", - "content-hash": "f42e69962756dd0af696c5611435ceec", + "content-hash": "ceca746323861f0ac218785a26d12193", "packages": [ { "name": "braintree/braintree_php", @@ -52,7 +51,7 @@ } ], "description": "Braintree PHP Client Library", - "time": "2017-02-16 19:59:04" + "time": "2017-02-16T19:59:04+00:00" }, { "name": "colinmollenhour/cache-backend-file", @@ -88,7 +87,7 @@ ], "description": "The stock Zend_Cache_Backend_File backend has extremely poor performance for cleaning by tags making it become unusable as the number of cached items increases. This backend makes many changes resulting in a huge performance boost, especially for tag cleaning.", "homepage": "https://github.com/colinmollenhour/Cm_Cache_Backend_File", - "time": "2016-05-02 16:24:47" + "time": "2016-05-02T16:24:47+00:00" }, { "name": "colinmollenhour/cache-backend-redis", @@ -124,7 +123,7 @@ ], "description": "Zend_Cache backend using Redis with full support for tags.", "homepage": "https://github.com/colinmollenhour/Cm_Cache_Backend_Redis", - "time": "2017-03-25 04:54:24" + "time": "2017-03-25T04:54:24+00:00" }, { "name": "colinmollenhour/credis", @@ -164,7 +163,7 @@ ], "description": "Credis is a lightweight interface to the Redis key-value store which wraps the phpredis library when available for better performance.", "homepage": "https://github.com/colinmollenhour/credis", - "time": "2017-07-05 15:32:38" + "time": "2017-07-05T15:32:38+00:00" }, { "name": "colinmollenhour/php-redis-session-abstract", @@ -201,7 +200,7 @@ ], "description": "A Redis-based session handler with optimistic locking", "homepage": "https://github.com/colinmollenhour/php-redis-session-abstract", - "time": "2017-03-22 16:13:03" + "time": "2017-03-22T16:13:03+00:00" }, { "name": "composer/ca-bundle", @@ -260,7 +259,7 @@ "ssl", "tls" ], - "time": "2017-09-11 07:24:36" + "time": "2017-09-11T07:24:36+00:00" }, { "name": "composer/composer", @@ -337,7 +336,7 @@ "dependency", "package" ], - "time": "2017-03-10 08:29:45" + "time": "2017-03-10T08:29:45+00:00" }, { "name": "composer/semver", @@ -399,7 +398,7 @@ "validation", "versioning" ], - "time": "2016-08-30 16:08:34" + "time": "2016-08-30T16:08:34+00:00" }, { "name": "composer/spdx-licenses", @@ -460,7 +459,7 @@ "spdx", "validator" ], - "time": "2017-04-03 19:08:52" + "time": "2017-04-03T19:08:52+00:00" }, { "name": "container-interop/container-interop", @@ -491,7 +490,7 @@ ], "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", "homepage": "https://github.com/container-interop/container-interop", - "time": "2017-02-14 19:40:03" + "time": "2017-02-14T19:40:03+00:00" }, { "name": "justinrainbow/json-schema", @@ -557,7 +556,7 @@ "json", "schema" ], - "time": "2017-10-10 13:22:37" + "time": "2017-10-10T13:22:37+00:00" }, { "name": "league/climate", @@ -606,7 +605,7 @@ "php", "terminal" ], - "time": "2015-01-18 14:31:58" + "time": "2015-01-18T14:31:58+00:00" }, { "name": "magento/composer", @@ -642,7 +641,7 @@ "AFL-3.0" ], "description": "Magento composer library helps to instantiate Composer application and run composer commands.", - "time": "2017-04-24 09:57:02" + "time": "2017-04-24T09:57:02+00:00" }, { "name": "magento/magento-composer-installer", @@ -721,7 +720,7 @@ "composer-installer", "magento" ], - "time": "2016-10-06 16:05:07" + "time": "2016-10-06T16:05:07+00:00" }, { "name": "magento/zendframework1", @@ -768,7 +767,7 @@ "ZF1", "framework" ], - "time": "2017-06-21 14:56:23" + "time": "2017-06-21T14:56:23+00:00" }, { "name": "monolog/monolog", @@ -846,7 +845,7 @@ "logging", "psr-3" ], - "time": "2017-06-19 01:22:40" + "time": "2017-06-19T01:22:40+00:00" }, { "name": "oyejorge/less.php", @@ -908,7 +907,7 @@ "php", "stylesheet" ], - "time": "2017-03-28 22:19:25" + "time": "2017-03-28T22:19:25+00:00" }, { "name": "paragonie/random_compat", @@ -956,7 +955,7 @@ "pseudorandom", "random" ], - "time": "2017-09-27 21:40:39" + "time": "2017-09-27T21:40:39+00:00" }, { "name": "pelago/emogrifier", @@ -1012,7 +1011,7 @@ ], "description": "Converts CSS styles into inline style attributes in your HTML code", "homepage": "http://www.pelagodesign.com/sidecar/emogrifier/", - "time": "2015-05-15 11:37:51" + "time": "2015-05-15T11:37:51+00:00" }, { "name": "phpseclib/phpseclib", @@ -1104,7 +1103,7 @@ "x.509", "x509" ], - "time": "2017-06-05 06:31:10" + "time": "2017-06-05T06:31:10+00:00" }, { "name": "psr/container", @@ -1153,7 +1152,7 @@ "container-interop", "psr" ], - "time": "2017-02-14 16:28:37" + "time": "2017-02-14T16:28:37+00:00" }, { "name": "psr/log", @@ -1200,7 +1199,7 @@ "psr", "psr-3" ], - "time": "2016-10-10 12:19:37" + "time": "2016-10-10T12:19:37+00:00" }, { "name": "ramsey/uuid", @@ -1282,7 +1281,7 @@ "identifier", "uuid" ], - "time": "2017-03-26 20:37:53" + "time": "2017-03-26T20:37:53+00:00" }, { "name": "seld/cli-prompt", @@ -1330,7 +1329,7 @@ "input", "prompt" ], - "time": "2017-03-18 11:32:45" + "time": "2017-03-18T11:32:45+00:00" }, { "name": "seld/jsonlint", @@ -1379,7 +1378,7 @@ "parser", "validator" ], - "time": "2017-06-18 15:11:04" + "time": "2017-06-18T15:11:04+00:00" }, { "name": "seld/phar-utils", @@ -1423,7 +1422,7 @@ "keywords": [ "phra" ], - "time": "2015-10-13 18:44:15" + "time": "2015-10-13T18:44:15+00:00" }, { "name": "sjparkinson/static-review", @@ -1476,7 +1475,7 @@ } ], "description": "An extendable framework for version control hooks.", - "time": "2014-09-22 08:40:36" + "time": "2014-09-22T08:40:36+00:00" }, { "name": "symfony/console", @@ -1537,7 +1536,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-10-01 21:00:16" + "time": "2017-10-01T21:00:16+00:00" }, { "name": "symfony/debug", @@ -1594,7 +1593,7 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2016-07-30 07:22:48" + "time": "2016-07-30T07:22:48+00:00" }, { "name": "symfony/event-dispatcher", @@ -1654,7 +1653,7 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2017-10-01 21:00:16" + "time": "2017-10-01T21:00:16+00:00" }, { "name": "symfony/filesystem", @@ -1703,7 +1702,7 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2017-10-03 13:33:10" + "time": "2017-10-03T13:33:10+00:00" }, { "name": "symfony/finder", @@ -1752,20 +1751,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2017-10-02 06:42:24" + "time": "2017-10-02T06:42:24+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.5.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803" + "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7c8fae0ac1d216eb54349e6a8baa57d515fe8803", - "reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", + "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", "shasum": "" }, "require": { @@ -1777,7 +1776,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -1811,7 +1810,7 @@ "portable", "shim" ], - "time": "2017-06-14 15:44:48" + "time": "2017-10-11T12:05:26+00:00" }, { "name": "symfony/process", @@ -1860,7 +1859,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-10-01 21:00:16" + "time": "2017-10-01T21:00:16+00:00" }, { "name": "tedivm/jshrink", @@ -1906,7 +1905,7 @@ "javascript", "minifier" ], - "time": "2015-07-04 07:35:09" + "time": "2015-07-04T07:35:09+00:00" }, { "name": "tubalmartin/cssmin", @@ -1959,7 +1958,7 @@ "minify", "yui" ], - "time": "2017-05-16 13:45:26" + "time": "2017-05-16T13:45:26+00:00" }, { "name": "zendframework/zend-captcha", @@ -2016,31 +2015,31 @@ "captcha", "zf2" ], - "time": "2017-02-23 08:09:44" + "time": "2017-02-23T08:09:44+00:00" }, { "name": "zendframework/zend-code", - "version": "3.1.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/zendframework/zend-code.git", - "reference": "2899c17f83a7207f2d7f53ec2f421204d3beea27" + "reference": "02944646c109fa53b6b6ab8b5269bb080fcdf5b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-code/zipball/2899c17f83a7207f2d7f53ec2f421204d3beea27", - "reference": "2899c17f83a7207f2d7f53ec2f421204d3beea27", + "url": "https://api.github.com/repos/zendframework/zend-code/zipball/02944646c109fa53b6b6ab8b5269bb080fcdf5b4", + "reference": "02944646c109fa53b6b6ab8b5269bb080fcdf5b4", "shasum": "" }, "require": { - "php": "^5.6 || 7.0.0 - 7.0.4 || ^7.0.6", + "php": "^7.1", "zendframework/zend-eventmanager": "^2.6 || ^3.0" }, "require-dev": { "doctrine/annotations": "~1.0", "ext-phar": "*", - "phpunit/phpunit": "^4.8.21", - "squizlabs/php_codesniffer": "^2.5", + "phpunit/phpunit": "^6.2.3", + "zendframework/zend-coding-standard": "^1.0.0", "zendframework/zend-stdlib": "^2.7 || ^3.0" }, "suggest": { @@ -2050,8 +2049,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev", - "dev-develop": "3.2-dev" + "dev-master": "3.2-dev", + "dev-develop": "3.3-dev" } }, "autoload": { @@ -2069,7 +2068,7 @@ "code", "zf2" ], - "time": "2016-10-24 13:23:32" + "time": "2017-07-23T13:06:00+00:00" }, { "name": "zendframework/zend-config", @@ -2125,7 +2124,7 @@ "config", "zf2" ], - "time": "2016-02-04 23:01:10" + "time": "2016-02-04T23:01:10+00:00" }, { "name": "zendframework/zend-console", @@ -2177,7 +2176,7 @@ "console", "zf2" ], - "time": "2016-02-09 17:15:12" + "time": "2016-02-09T17:15:12+00:00" }, { "name": "zendframework/zend-crypt", @@ -2227,7 +2226,7 @@ "crypt", "zf2" ], - "time": "2016-02-03 23:46:30" + "time": "2016-02-03T23:46:30+00:00" }, { "name": "zendframework/zend-db", @@ -2284,7 +2283,7 @@ "db", "zf2" ], - "time": "2016-08-09 19:28:55" + "time": "2016-08-09T19:28:55+00:00" }, { "name": "zendframework/zend-di", @@ -2331,7 +2330,7 @@ "di", "zf2" ], - "time": "2016-04-25 20:58:11" + "time": "2016-04-25T20:58:11+00:00" }, { "name": "zendframework/zend-escaper", @@ -2375,7 +2374,7 @@ "escaper", "zf2" ], - "time": "2016-06-30 19:48:38" + "time": "2016-06-30T19:48:38+00:00" }, { "name": "zendframework/zend-eventmanager", @@ -2422,7 +2421,7 @@ "eventmanager", "zf2" ], - "time": "2016-02-18 20:49:05" + "time": "2016-02-18T20:49:05+00:00" }, { "name": "zendframework/zend-filter", @@ -2482,7 +2481,7 @@ "filter", "zf2" ], - "time": "2017-05-17 20:56:17" + "time": "2017-05-17T20:56:17+00:00" }, { "name": "zendframework/zend-form", @@ -2559,39 +2558,39 @@ "form", "zf2" ], - "time": "2017-05-18 14:59:53" + "time": "2017-05-18T14:59:53+00:00" }, { "name": "zendframework/zend-http", - "version": "2.6.0", + "version": "2.7.0", "source": { "type": "git", "url": "https://github.com/zendframework/zend-http.git", - "reference": "09f4d279f46d86be63171ff62ee0f79eca878678" + "reference": "78aa510c0ea64bfb2aa234f50c4f232c9531acfa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-http/zipball/09f4d279f46d86be63171ff62ee0f79eca878678", - "reference": "09f4d279f46d86be63171ff62ee0f79eca878678", + "url": "https://api.github.com/repos/zendframework/zend-http/zipball/78aa510c0ea64bfb2aa234f50c4f232c9531acfa", + "reference": "78aa510c0ea64bfb2aa234f50c4f232c9531acfa", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0", - "zendframework/zend-loader": "^2.5", - "zendframework/zend-stdlib": "^2.5 || ^3.0", - "zendframework/zend-uri": "^2.5", - "zendframework/zend-validator": "^2.5" + "php": "^5.6 || ^7.0", + "zendframework/zend-loader": "^2.5.1", + "zendframework/zend-stdlib": "^3.1 || ^2.7.7", + "zendframework/zend-uri": "^2.5.2", + "zendframework/zend-validator": "^2.10.1" }, "require-dev": { - "phpunit/phpunit": "^4.0", + "phpunit/phpunit": "^6.4.1 || ^5.7.15", "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-config": "^2.5" + "zendframework/zend-config": "^3.1 || ^2.6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev", - "dev-develop": "2.7-dev" + "dev-master": "2.7-dev", + "dev-develop": "2.8-dev" } }, "autoload": { @@ -2606,10 +2605,13 @@ "description": "provides an easy interface for performing Hyper-Text Transfer Protocol (HTTP) requests", "homepage": "https://github.com/zendframework/zend-http", "keywords": [ + "ZendFramework", "http", - "zf2" + "http client", + "zend", + "zf" ], - "time": "2017-01-31 14:41:02" + "time": "2017-10-13T12:06:24+00:00" }, { "name": "zendframework/zend-hydrator", @@ -2667,7 +2669,7 @@ "hydrator", "zf2" ], - "time": "2016-02-18 22:38:26" + "time": "2016-02-18T22:38:26+00:00" }, { "name": "zendframework/zend-i18n", @@ -2734,7 +2736,7 @@ "i18n", "zf2" ], - "time": "2017-05-17 17:00:12" + "time": "2017-05-17T17:00:12+00:00" }, { "name": "zendframework/zend-inputfilter", @@ -2789,7 +2791,7 @@ "inputfilter", "zf2" ], - "time": "2017-05-18 14:20:56" + "time": "2017-05-18T14:20:56+00:00" }, { "name": "zendframework/zend-json", @@ -2844,7 +2846,7 @@ "json", "zf2" ], - "time": "2016-02-04 21:20:26" + "time": "2016-02-04T21:20:26+00:00" }, { "name": "zendframework/zend-loader", @@ -2888,7 +2890,7 @@ "loader", "zf2" ], - "time": "2015-06-03 14:05:47" + "time": "2015-06-03T14:05:47+00:00" }, { "name": "zendframework/zend-log", @@ -2959,7 +2961,7 @@ "logging", "zf2" ], - "time": "2017-05-17 16:03:26" + "time": "2017-05-17T16:03:26+00:00" }, { "name": "zendframework/zend-math", @@ -3009,7 +3011,7 @@ "math", "zf2" ], - "time": "2016-04-07 16:29:53" + "time": "2016-04-07T16:29:53+00:00" }, { "name": "zendframework/zend-modulemanager", @@ -3067,7 +3069,7 @@ "modulemanager", "zf2" ], - "time": "2017-07-11 19:39:57" + "time": "2017-07-11T19:39:57+00:00" }, { "name": "zendframework/zend-mvc", @@ -3154,7 +3156,7 @@ "mvc", "zf2" ], - "time": "2016-02-23 15:24:59" + "time": "2016-02-23T15:24:59+00:00" }, { "name": "zendframework/zend-serializer", @@ -3211,7 +3213,7 @@ "serializer", "zf2" ], - "time": "2016-06-21 17:01:55" + "time": "2016-06-21T17:01:55+00:00" }, { "name": "zendframework/zend-server", @@ -3257,7 +3259,7 @@ "server", "zf2" ], - "time": "2016-06-20 22:27:55" + "time": "2016-06-20T22:27:55+00:00" }, { "name": "zendframework/zend-servicemanager", @@ -3309,7 +3311,7 @@ "servicemanager", "zf2" ], - "time": "2016-12-19 19:14:29" + "time": "2016-12-19T19:14:29+00:00" }, { "name": "zendframework/zend-session", @@ -3375,7 +3377,7 @@ "session", "zf2" ], - "time": "2017-06-19 21:31:39" + "time": "2017-06-19T21:31:39+00:00" }, { "name": "zendframework/zend-soap", @@ -3427,7 +3429,7 @@ "soap", "zf2" ], - "time": "2016-04-21 16:06:27" + "time": "2016-04-21T16:06:27+00:00" }, { "name": "zendframework/zend-stdlib", @@ -3486,7 +3488,7 @@ "stdlib", "zf2" ], - "time": "2016-04-12 21:17:31" + "time": "2016-04-12T21:17:31+00:00" }, { "name": "zendframework/zend-text", @@ -3533,7 +3535,7 @@ "text", "zf2" ], - "time": "2016-02-08 19:03:52" + "time": "2016-02-08T19:03:52+00:00" }, { "name": "zendframework/zend-uri", @@ -3580,7 +3582,7 @@ "uri", "zf2" ], - "time": "2016-02-17 22:38:51" + "time": "2016-02-17T22:38:51+00:00" }, { "name": "zendframework/zend-validator", @@ -3651,7 +3653,7 @@ "validator", "zf2" ], - "time": "2017-08-22 14:19:23" + "time": "2017-08-22T14:19:23+00:00" }, { "name": "zendframework/zend-view", @@ -3738,38 +3740,38 @@ "view", "zf2" ], - "time": "2017-03-21 15:05:56" + "time": "2017-03-21T15:05:56+00:00" } ], "packages-dev": [ { "name": "doctrine/instantiator", - "version": "1.0.5", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", "shasum": "" }, "require": { - "php": ">=5.3,<8.0-DEV" + "php": "^7.1" }, "require-dev": { "athletic/athletic": "~0.1.8", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" + "phpunit/phpunit": "^6.2.3", + "squizlabs/php_codesniffer": "^3.0.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -3794,7 +3796,7 @@ "constructor", "instantiate" ], - "time": "2015-06-14 21:17:01" + "time": "2017-07-22T11:58:36+00:00" }, { "name": "friendsofphp/php-cs-fixer", @@ -3864,7 +3866,7 @@ } ], "description": "A tool to automatically fix PHP code style", - "time": "2017-03-31 12:59:38" + "time": "2017-03-31T12:59:38+00:00" }, { "name": "ircmaxell/password-compat", @@ -3906,7 +3908,7 @@ "hashing", "password" ], - "time": "2014-11-20 16:49:30" + "time": "2014-11-20T16:49:30+00:00" }, { "name": "lusitanian/oauth", @@ -3973,7 +3975,7 @@ "oauth", "security" ], - "time": "2016-07-12 22:15:40" + "time": "2016-07-12T22:15:40+00:00" }, { "name": "myclabs/deep-copy", @@ -4015,7 +4017,7 @@ "object", "object graph" ], - "time": "2017-04-12 18:52:22" + "time": "2017-04-12T18:52:22+00:00" }, { "name": "pdepend/pdepend", @@ -4055,7 +4057,7 @@ "BSD-3-Clause" ], "description": "Official version of pdepend to be handled with Composer", - "time": "2017-01-19 14:23:36" + "time": "2017-01-19T14:23:36+00:00" }, { "name": "phar-io/manifest", @@ -4110,7 +4112,7 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-03-05 18:14:27" + "time": "2017-03-05T18:14:27+00:00" }, { "name": "phar-io/version", @@ -4157,7 +4159,7 @@ } ], "description": "Library for handling version information and constraints", - "time": "2017-03-05 17:38:23" + "time": "2017-03-05T17:38:23+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -4211,7 +4213,7 @@ "reflection", "static analysis" ], - "time": "2017-09-11 18:02:19" + "time": "2017-09-11T18:02:19+00:00" }, { "name": "phpdocumentor/reflection-docblock", @@ -4256,7 +4258,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-08-30 18:51:59" + "time": "2017-08-30T18:51:59+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -4303,7 +4305,7 @@ "email": "me@mikevanriel.com" } ], - "time": "2017-07-14 14:27:02" + "time": "2017-07-14T14:27:02+00:00" }, { "name": "phpmd/phpmd", @@ -4369,7 +4371,7 @@ "phpmd", "pmd" ], - "time": "2017-01-20 14:41:10" + "time": "2017-01-20T14:41:10+00:00" }, { "name": "phpspec/prophecy", @@ -4432,7 +4434,7 @@ "spy", "stub" ], - "time": "2017-09-04 11:05:03" + "time": "2017-09-04T11:05:03+00:00" }, { "name": "phpunit/php-code-coverage", @@ -4496,7 +4498,7 @@ "testing", "xunit" ], - "time": "2017-08-03 12:40:43" + "time": "2017-08-03T12:40:43+00:00" }, { "name": "phpunit/php-file-iterator", @@ -4543,7 +4545,7 @@ "filesystem", "iterator" ], - "time": "2016-10-03 07:40:28" + "time": "2016-10-03T07:40:28+00:00" }, { "name": "phpunit/php-text-template", @@ -4584,7 +4586,7 @@ "keywords": [ "template" ], - "time": "2015-06-21 13:50:34" + "time": "2015-06-21T13:50:34+00:00" }, { "name": "phpunit/php-timer", @@ -4633,7 +4635,7 @@ "keywords": [ "timer" ], - "time": "2017-02-26 11:10:40" + "time": "2017-02-26T11:10:40+00:00" }, { "name": "phpunit/php-token-stream", @@ -4682,7 +4684,7 @@ "keywords": [ "tokenizer" ], - "time": "2017-08-20 05:47:52" + "time": "2017-08-20T05:47:52+00:00" }, { "name": "phpunit/phpunit", @@ -4766,7 +4768,7 @@ "testing", "xunit" ], - "time": "2017-08-03 13:59:28" + "time": "2017-08-03T13:59:28+00:00" }, { "name": "phpunit/phpunit-mock-objects", @@ -4825,7 +4827,7 @@ "mock", "xunit" ], - "time": "2017-08-03 14:08:16" + "time": "2017-08-03T14:08:16+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -4870,7 +4872,7 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04 06:30:41" + "time": "2017-03-04T06:30:41+00:00" }, { "name": "sebastian/comparator", @@ -4934,7 +4936,7 @@ "compare", "equality" ], - "time": "2017-03-03 06:26:08" + "time": "2017-03-03T06:26:08+00:00" }, { "name": "sebastian/diff", @@ -4986,7 +4988,7 @@ "keywords": [ "diff" ], - "time": "2017-05-22 07:24:03" + "time": "2017-05-22T07:24:03+00:00" }, { "name": "sebastian/environment", @@ -5036,7 +5038,7 @@ "environment", "hhvm" ], - "time": "2017-07-01 08:51:00" + "time": "2017-07-01T08:51:00+00:00" }, { "name": "sebastian/exporter", @@ -5103,7 +5105,7 @@ "export", "exporter" ], - "time": "2017-04-03 13:19:02" + "time": "2017-04-03T13:19:02+00:00" }, { "name": "sebastian/finder-facade", @@ -5142,7 +5144,7 @@ ], "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", "homepage": "https://github.com/sebastianbergmann/finder-facade", - "time": "2016-02-17 07:02:23" + "time": "2016-02-17T07:02:23+00:00" }, { "name": "sebastian/global-state", @@ -5193,7 +5195,7 @@ "keywords": [ "global state" ], - "time": "2017-04-27 15:39:26" + "time": "2017-04-27T15:39:26+00:00" }, { "name": "sebastian/object-enumerator", @@ -5240,7 +5242,7 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03 12:35:26" + "time": "2017-08-03T12:35:26+00:00" }, { "name": "sebastian/object-reflector", @@ -5285,7 +5287,7 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29 09:07:27" + "time": "2017-03-29T09:07:27+00:00" }, { "name": "sebastian/phpcpd", @@ -5336,7 +5338,7 @@ ], "description": "Copy/Paste Detector (CPD) for PHP code.", "homepage": "https://github.com/sebastianbergmann/phpcpd", - "time": "2016-04-17 19:32:49" + "time": "2016-04-17T19:32:49+00:00" }, { "name": "sebastian/recursion-context", @@ -5389,7 +5391,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-03 06:23:57" + "time": "2017-03-03T06:23:57+00:00" }, { "name": "sebastian/resource-operations", @@ -5431,7 +5433,7 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28 20:34:47" + "time": "2015-07-28T20:34:47+00:00" }, { "name": "sebastian/version", @@ -5474,7 +5476,7 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03 07:35:21" + "time": "2016-10-03T07:35:21+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -5525,7 +5527,7 @@ "phpcs", "standards" ], - "time": "2017-06-14 01:23:49" + "time": "2017-06-14T01:23:49+00:00" }, { "name": "symfony/config", @@ -5587,7 +5589,7 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2017-10-04 18:56:58" + "time": "2017-10-04T18:56:58+00:00" }, { "name": "symfony/dependency-injection", @@ -5657,20 +5659,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2017-10-04 17:15:30" + "time": "2017-10-04T17:15:30+00:00" }, { "name": "symfony/polyfill-php54", - "version": "v1.5.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php54.git", - "reference": "b7763422a5334c914ef0298ed21b253d25913a6e" + "reference": "d7810a14b2c6c1aff415e1bb755f611b3d5327bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php54/zipball/b7763422a5334c914ef0298ed21b253d25913a6e", - "reference": "b7763422a5334c914ef0298ed21b253d25913a6e", + "url": "https://api.github.com/repos/symfony/polyfill-php54/zipball/d7810a14b2c6c1aff415e1bb755f611b3d5327bc", + "reference": "d7810a14b2c6c1aff415e1bb755f611b3d5327bc", "shasum": "" }, "require": { @@ -5679,7 +5681,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -5715,20 +5717,20 @@ "portable", "shim" ], - "time": "2017-06-14 15:44:48" + "time": "2017-10-11T12:05:26+00:00" }, { "name": "symfony/polyfill-php55", - "version": "v1.5.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php55.git", - "reference": "29b1381d66f16e0581aab0b9f678ccf073288f68" + "reference": "b64e7f0c37ecf144ecc16668936eef94e628fbfd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/29b1381d66f16e0581aab0b9f678ccf073288f68", - "reference": "29b1381d66f16e0581aab0b9f678ccf073288f68", + "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/b64e7f0c37ecf144ecc16668936eef94e628fbfd", + "reference": "b64e7f0c37ecf144ecc16668936eef94e628fbfd", "shasum": "" }, "require": { @@ -5738,7 +5740,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -5771,20 +5773,20 @@ "portable", "shim" ], - "time": "2017-06-14 15:44:48" + "time": "2017-10-11T12:05:26+00:00" }, { "name": "symfony/polyfill-php70", - "version": "v1.5.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "b6482e68974486984f59449ecea1fbbb22ff840f" + "reference": "0442b9c0596610bd24ae7b5f0a6cdbbc16d9fcff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/b6482e68974486984f59449ecea1fbbb22ff840f", - "reference": "b6482e68974486984f59449ecea1fbbb22ff840f", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/0442b9c0596610bd24ae7b5f0a6cdbbc16d9fcff", + "reference": "0442b9c0596610bd24ae7b5f0a6cdbbc16d9fcff", "shasum": "" }, "require": { @@ -5794,7 +5796,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -5830,20 +5832,20 @@ "portable", "shim" ], - "time": "2017-06-14 15:44:48" + "time": "2017-10-11T12:05:26+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.5.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "8abc9097f5001d310f0edba727469c988acc6ea7" + "reference": "6de4f4884b97abbbed9f0a84a95ff2ff77254254" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/8abc9097f5001d310f0edba727469c988acc6ea7", - "reference": "8abc9097f5001d310f0edba727469c988acc6ea7", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/6de4f4884b97abbbed9f0a84a95ff2ff77254254", + "reference": "6de4f4884b97abbbed9f0a84a95ff2ff77254254", "shasum": "" }, "require": { @@ -5852,7 +5854,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -5885,20 +5887,20 @@ "portable", "shim" ], - "time": "2017-07-11 13:25:55" + "time": "2017-10-11T12:05:26+00:00" }, { "name": "symfony/polyfill-xml", - "version": "v1.5.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-xml.git", - "reference": "7d536462e554da7b05600a926303bf9b99153275" + "reference": "d7bcb5c3bb1832c532379df50825c08f43a64134" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-xml/zipball/7d536462e554da7b05600a926303bf9b99153275", - "reference": "7d536462e554da7b05600a926303bf9b99153275", + "url": "https://api.github.com/repos/symfony/polyfill-xml/zipball/d7bcb5c3bb1832c532379df50825c08f43a64134", + "reference": "d7bcb5c3bb1832c532379df50825c08f43a64134", "shasum": "" }, "require": { @@ -5908,7 +5910,7 @@ "type": "metapackage", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.6-dev" } }, "notification-url": "https://packagist.org/downloads/", @@ -5933,7 +5935,7 @@ "portable", "shim" ], - "time": "2017-06-14 15:44:48" + "time": "2017-10-11T12:05:26+00:00" }, { "name": "symfony/stopwatch", @@ -5982,7 +5984,7 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2017-10-02 06:42:24" + "time": "2017-10-02T06:42:24+00:00" }, { "name": "theseer/fdomdocument", @@ -6022,7 +6024,7 @@ ], "description": "The classes contained within this repository extend the standard DOM to use exceptions at all occasions of errors instead of PHP warnings or notices. They also add various custom methods and shortcuts for convenience and to simplify the usage of DOM.", "homepage": "https://github.com/theseer/fDOMDocument", - "time": "2017-06-30 11:53:12" + "time": "2017-06-30T11:53:12+00:00" }, { "name": "theseer/tokenizer", @@ -6062,7 +6064,7 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2017-04-07 12:08:54" + "time": "2017-04-07T12:08:54+00:00" }, { "name": "webmozart/assert", @@ -6112,7 +6114,7 @@ "check", "validate" ], - "time": "2016-11-23 20:04:58" + "time": "2016-11-23T20:04:58+00:00" } ], "aliases": [], From beccd7dd47b6d8421cb50863acb476d9b9bcec4b Mon Sep 17 00:00:00 2001 From: Thiago Lima Date: Fri, 20 Oct 2017 10:37:38 +0200 Subject: [PATCH 072/194] #11211 Fix Store View switcher, update integration test --- .../integration/testsuite/Magento/Store/Model/StoreTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php b/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php index e62436460998f..67fe8d1dedea9 100644 --- a/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php +++ b/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php @@ -274,7 +274,7 @@ public function testGetCurrentUrl() $this->model->load('admin'); $this->model->expects($this->any())->method('getUrl')->will($this->returnValue('http://localhost/index.php')); $this->assertStringEndsWith('default', $this->model->getCurrentUrl()); - $this->assertStringEndsNotWith('default', $this->model->getCurrentUrl(false)); + $this->assertStringEndsWith('default', $this->model->getCurrentUrl(false)); } /** From fea77c70d62e9c9259596dd0a96a4993f200380b Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Wed, 18 Oct 2017 12:04:49 +0300 Subject: [PATCH 073/194] Checkout place order exception when using a new address - Added doc block parsing for interceptors --- app/code/Magento/Quote/Model/Quote.php | 2 +- .../Magento/Quote/Model/QuoteTest.php | 2 +- .../Reflection/Test/Unit/Fixture/TSample.php | 25 +++++++ .../Test/Unit/Fixture/TSampleInterface.php | 21 ++++++ .../Test/Unit/TypeProcessorTest.php | 34 ++++++++- .../Framework/Reflection/TypeProcessor.php | 73 ++++++++++++++----- 6 files changed, 137 insertions(+), 20 deletions(-) create mode 100644 lib/internal/Magento/Framework/Reflection/Test/Unit/Fixture/TSample.php create mode 100644 lib/internal/Magento/Framework/Reflection/Test/Unit/Fixture/TSampleInterface.php diff --git a/app/code/Magento/Quote/Model/Quote.php b/app/code/Magento/Quote/Model/Quote.php index bf2c6bbc57d95..7741d3b0f7657 100644 --- a/app/code/Magento/Quote/Model/Quote.php +++ b/app/code/Magento/Quote/Model/Quote.php @@ -1057,7 +1057,7 @@ public function addCustomerAddress(\Magento\Customer\Api\Data\AddressInterface $ public function updateCustomerData(\Magento\Customer\Api\Data\CustomerInterface $customer) { $quoteCustomer = $this->getCustomer(); - $this->dataObjectHelper->mergeDataObjects(get_class($quoteCustomer), $quoteCustomer, $customer); + $this->dataObjectHelper->mergeDataObjects(CustomerInterface::class, $quoteCustomer, $customer); $this->setCustomer($quoteCustomer); return $this; } diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php index 258b14bf6e0d3..ecd8b62b122d4 100644 --- a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php @@ -393,7 +393,7 @@ protected function _getCustomerDataArray() \Magento\Customer\Model\Data\Customer::DOB => '2014-02-03 00:00:00', \Magento\Customer\Model\Data\Customer::EMAIL => 'qa@example.com', \Magento\Customer\Model\Data\Customer::FIRSTNAME => 'Joe', - \Magento\Customer\Model\Data\Customer::GENDER => 'Male', + \Magento\Customer\Model\Data\Customer::GENDER => 0, \Magento\Customer\Model\Data\Customer::GROUP_ID => \Magento\Customer\Model\GroupManagement::NOT_LOGGED_IN_ID, \Magento\Customer\Model\Data\Customer::ID => 1, diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/Fixture/TSample.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/Fixture/TSample.php new file mode 100644 index 0000000000000..1d78f9ed0a7d8 --- /dev/null +++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/Fixture/TSample.php @@ -0,0 +1,25 @@ +assertEquals("resNameMethodName", $this->_typeProcessor->getOperationName("resName", "methodName")); } + + /** + * Checks a case when method has only `@inheritdoc` annotation. + */ + public function testGetReturnTypeWithInheritDocBlock() + { + $expected = [ + 'type' => 'string', + 'isRequired' => true, + 'description' => null, + 'parameterCount' => 0 + ]; + + $classReflection = new ClassReflection(TSample::class); + $methodReflection = $classReflection->getMethod('getPropertyName'); + + self::assertEquals($expected, $this->_typeProcessor->getGetterReturnType($methodReflection)); + } + + /** + * Checks a case when method and parent interface don't have `@return` annotation. + * + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Getter return type must be specified using @return annotation. See Magento\Framework\Reflection\Test\Unit\Fixture\TSample::getName() + */ + public function testGetReturnTypeWithoutReturnTag() + { + $classReflection = new ClassReflection(TSample::class); + $methodReflection = $classReflection->getMethod('getName'); + $this->_typeProcessor->getGetterReturnType($methodReflection); + } } diff --git a/lib/internal/Magento/Framework/Reflection/TypeProcessor.php b/lib/internal/Magento/Framework/Reflection/TypeProcessor.php index 5d6054056d35e..74c1bc95b208b 100644 --- a/lib/internal/Magento/Framework/Reflection/TypeProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/TypeProcessor.php @@ -8,6 +8,7 @@ use Magento\Framework\Exception\SerializationException; use Magento\Framework\Phrase; use Zend\Code\Reflection\ClassReflection; +use Zend\Code\Reflection\DocBlock\Tag\ReturnTag; use Zend\Code\Reflection\DocBlockReflection; use Zend\Code\Reflection\MethodReflection; use Zend\Code\Reflection\ParameterReflection; @@ -16,6 +17,7 @@ * Type processor of config reader properties * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) this suppress MUST be removed after removing deprecated methods. */ class TypeProcessor { @@ -275,22 +277,7 @@ protected function dataObjectGetterDescriptionToFieldDescription($shortDescripti */ public function getGetterReturnType($methodReflection) { - $methodDocBlock = $methodReflection->getDocBlock(); - if (!$methodDocBlock) { - throw new \InvalidArgumentException( - "Each getter must have description with @return annotation. " - . "See {$methodReflection->getDeclaringClass()->getName()}::{$methodReflection->getName()}()" - ); - } - $returnAnnotations = $methodDocBlock->getTags('return'); - if (empty($returnAnnotations)) { - throw new \InvalidArgumentException( - "Getter return type must be specified using @return annotation. " - . "See {$methodReflection->getDeclaringClass()->getName()}::{$methodReflection->getName()}()" - ); - } - /** @var \Zend\Code\Reflection\DocBlock\Tag\ReturnTag $returnAnnotation */ - $returnAnnotation = current($returnAnnotations); + $returnAnnotation = $this->getMethodReturnAnnotation($methodReflection); $types = $returnAnnotation->getTypes(); $returnType = current($types); $nullable = in_array('null', $types); @@ -362,7 +349,7 @@ public function isTypeSimple($type) self::NORMALIZED_INT_TYPE, self::NORMALIZED_FLOAT_TYPE, self::NORMALIZED_DOUBLE_TYPE, - self::NORMALIZED_BOOLEAN_TYPE + self::NORMALIZED_BOOLEAN_TYPE, ] ); } @@ -708,4 +695,56 @@ private function getNormalizedType($type) } return $type; } + + /** + * Parses `return` annotation from reflection method. + * + * @param MethodReflection $methodReflection + * @return ReturnTag + * @throws \InvalidArgumentException if doc block is empty or `@return` annotation doesn't exist + */ + private function getMethodReturnAnnotation(MethodReflection $methodReflection) + { + $methodName = $methodReflection->getName(); + $returnAnnotations = $this->getReturnFromDocBlock($methodReflection); + if (empty($returnAnnotations)) { + // method can inherit doc block from implemented interface, like for interceptors + $implemented = $methodReflection->getDeclaringClass()->getInterfaces(); + /** @var ClassReflection $parentClassReflection */ + foreach ($implemented as $parentClassReflection) { + if ($parentClassReflection->hasMethod($methodName)) { + $returnAnnotations = $this->getReturnFromDocBlock( + $parentClassReflection->getMethod($methodName) + ); + break; + } + } + // throw an exception if even implemented interface doesn't have return annotations + if (empty($returnAnnotations)) { + throw new \InvalidArgumentException( + "Getter return type must be specified using @return annotation. " + . "See {$methodReflection->getDeclaringClass()->getName()}::{$methodName}()" + ); + } + } + return $returnAnnotations; + } + + /** + * Parses `return` annotation from doc block. + * + * @param MethodReflection $methodReflection + * @return ReturnTag + */ + private function getReturnFromDocBlock(MethodReflection $methodReflection) + { + $methodDocBlock = $methodReflection->getDocBlock(); + if (!$methodDocBlock) { + throw new \InvalidArgumentException( + "Each getter must have a doc block. " + . "See {$methodReflection->getDeclaringClass()->getName()}::{$methodReflection->getName()}()" + ); + } + return current($methodDocBlock->getTags('return')); + } } From 1b3f6aec94444d7e60e27e3cbba40614a6556a7c Mon Sep 17 00:00:00 2001 From: Joan He Date: Fri, 20 Oct 2017 12:23:03 -0500 Subject: [PATCH 074/194] MAGETWO-82125: Display advertisement popup at the 1st time per admin login --- .../Model/AdvertisementFlagManager.php | 60 ---------- .../Model/Condition/CanViewNotification.php | 34 ++++-- .../Model/ResourceModel/Viewer/Logger.php | 106 ++++++++++++++++++ .../Advertisement/Model/Viewer/Log.php | 26 +++++ .../Advertisement/Setup/InstallSchema.php | 69 ++++++++++++ .../Model/AdvertisementFlagManagerTest.php | 61 ---------- .../Condition/CanViewNotificationTest.php | 83 +++++++++----- app/code/Magento/Advertisement/etc/module.xml | 2 +- .../Model/ResourceModel/Viewer/LoggerTest.php | 62 ++++++++++ 9 files changed, 343 insertions(+), 160 deletions(-) delete mode 100644 app/code/Magento/Advertisement/Model/AdvertisementFlagManager.php create mode 100644 app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php create mode 100644 app/code/Magento/Advertisement/Model/Viewer/Log.php create mode 100644 app/code/Magento/Advertisement/Setup/InstallSchema.php delete mode 100644 app/code/Magento/Advertisement/Test/Unit/Model/AdvertisementFlagManagerTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Advertisement/Model/ResourceModel/Viewer/LoggerTest.php diff --git a/app/code/Magento/Advertisement/Model/AdvertisementFlagManager.php b/app/code/Magento/Advertisement/Model/AdvertisementFlagManager.php deleted file mode 100644 index 88a95f5df63b1..0000000000000 --- a/app/code/Magento/Advertisement/Model/AdvertisementFlagManager.php +++ /dev/null @@ -1,60 +0,0 @@ -flagManager = $flagManager; - } - - /** - * Sets the flag to indicate the user was notified about Analytic services - * @param $userId - * @return bool - */ - public function setNotifiedUser($userId) - { - $flagCode = self::NOTIFICATION_SEEN . $userId; - return $this->flagManager->saveFlag($flagCode, 1); - } - - /** - * Returns the flag data if the user was notified about Analytic services - * @param $userId - * @return bool - */ - public function isUserNotified($userId) - { - if ($this->flagManager->getFlagData(self::NOTIFICATION_SEEN . $userId)) { - return true; - } - - return false; - } -} diff --git a/app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php b/app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php index 1bd28ce95e0a3..b54f4fe928fb6 100644 --- a/app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php @@ -5,9 +5,10 @@ */ namespace Magento\Advertisement\Model\Condition; +use Magento\Advertisement\Model\ResourceModel\Viewer\Logger; use Magento\Backend\Model\Auth\Session; +use Magento\Framework\App\ProductMetadataInterface; use Magento\Framework\View\Layout\Condition\VisibilityConditionInterface; -use Magento\Advertisement\Model\AdvertisementFlagManager; /** * Class CanViewNotification @@ -23,27 +24,34 @@ class CanViewNotification implements VisibilityConditionInterface const NAME = 'can_view_notification'; /** - * @var AdvertisementFlagManager + * @var Logger */ - private $advertisementFlagManager; + private $viewerLogger; /** * @var Session */ private $session; + /** + * @var ProductMetadataInterface + */ + private $productMetadata; + /** * CanViewNotification constructor. * - * @param AdvertisementFlagManager $advertisementFlagManager + * @param Logger $viewerLogger * @param Session $session */ public function __construct( - AdvertisementFlagManager $advertisementFlagManager, - Session $session + Logger $viewerLogger, + Session $session, + ProductMetadataInterface $productMetadata ) { - $this->advertisementFlagManager = $advertisementFlagManager; + $this->viewerLogger = $viewerLogger; $this->session = $session; + $this->productMetadata = $productMetadata; } /** @@ -54,11 +62,17 @@ public function __construct( public function isVisible(array $arguments) { $userId = $this->session->getUser()->getId(); - if ($this->advertisementFlagManager->isUserNotified($userId)) { + $viewerLog = $this->viewerLogger->get($userId); + $version = $this->productMetadata->getVersion(); + if ($viewerLog == null + || $viewerLog->getLastViewVersion() == null + || $viewerLog->getLastViewVersion() < $version + ) { + $this->viewerLogger->log($userId, $version); + return true; + } else { return false; } - - return $this->advertisementFlagManager->setNotifiedUser($userId); } /** diff --git a/app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php b/app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php new file mode 100644 index 0000000000000..a38b888de4d64 --- /dev/null +++ b/app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php @@ -0,0 +1,106 @@ +resource = $resource; + $this->logFactory = $logFactory; + } + + /** + * Save (insert new or update existing) log. + * + * @param int $viewerId + * @param string $lastViewVersion + * @return $this + */ + public function log($viewerId, $lastViewVersion) + { + /** @var \Magento\Framework\DB\Adapter\AdapterInterface $connection */ + $connection = $this->resource->getConnection(ResourceConnection::DEFAULT_CONNECTION); + + $connection->insertOnDuplicate( + $this->resource->getTableName(self::TABLE_NAME ), + [ + 'viewer_id' => $viewerId, + 'last_view_version' => $lastViewVersion + ], + ['viewer_id', 'last_view_version'] + ); + + return $this; + } + + /** + * Get log by viewer Id. + * + * @param int $viewerId + * @return Log|null + */ + public function get($viewerId) + { + $data = $this->loadLogData($viewerId); + if (is_array($data)) { + return $this->logFactory->create(['data' => $data]); + } else { + return null; + } + } + + /** + * Load advertisement viewer log data by viewer id + * + * @param int $viewerId + * @return array + */ + private function loadLogData($viewerId) + { + $connection = $this->resource->getConnection(); + + $select = $connection->select() + ->from( + $this->resource->getTableName(self::TABLE_NAME) + )->where( + 'viewer_id = ?', + $viewerId + )->order( + 'id DESC' + )->limit(1); + + return $connection->fetchRow($select); + } +} diff --git a/app/code/Magento/Advertisement/Model/Viewer/Log.php b/app/code/Magento/Advertisement/Model/Viewer/Log.php new file mode 100644 index 0000000000000..fa19461f63a25 --- /dev/null +++ b/app/code/Magento/Advertisement/Model/Viewer/Log.php @@ -0,0 +1,26 @@ +getData('id'); + } + + public function getViewerId() + { + return $this->getData('viewer_id'); + } + + public function getLastViewVersion() + { + return $this->getData('last_view_version'); + } +} diff --git a/app/code/Magento/Advertisement/Setup/InstallSchema.php b/app/code/Magento/Advertisement/Setup/InstallSchema.php new file mode 100644 index 0000000000000..1bc1d433d84e8 --- /dev/null +++ b/app/code/Magento/Advertisement/Setup/InstallSchema.php @@ -0,0 +1,69 @@ +startSetup(); + + /** + * Create table 'advertisement_viewer_log' + */ + $table = $setup->getConnection()->newTable( + $setup->getTable('advertisement_viewer_log') + )->addColumn( + 'id', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], + 'Log ID' + )->addColumn( + 'viewer_id', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['unsigned' => true, 'nullable' => false], + 'Viewer admin user ID' + )->addColumn( + 'last_view_version', + \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + 10, + ['nullable' => true], + 'Viewer last view on product version' + )->addIndex( + $setup->getIdxName( + 'advertisement_viewer_log', + ['viewer_id'], + \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE + ), + ['viewer_id'], + ['type' => \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE] + )->addForeignKey( + $setup->getFkName('advertisement_viewer_log', 'viewer_id', 'admin_user', 'user_id'), + 'viewer_id', + $setup->getTable('admin_user'), + 'user_id', + Table::ACTION_CASCADE + )->setComment( + 'Advertisement Viewer Log Table' + ); + $setup->getConnection()->createTable($table); + + $setup->endSetup(); + } +} diff --git a/app/code/Magento/Advertisement/Test/Unit/Model/AdvertisementFlagManagerTest.php b/app/code/Magento/Advertisement/Test/Unit/Model/AdvertisementFlagManagerTest.php deleted file mode 100644 index ddcbdbd6c1a0b..0000000000000 --- a/app/code/Magento/Advertisement/Test/Unit/Model/AdvertisementFlagManagerTest.php +++ /dev/null @@ -1,61 +0,0 @@ -flagManagerMock = $this->getMockBuilder(FlagManager::class) - ->disableOriginalConstructor() - ->getMock(); - $objectManager = new ObjectManager($this); - $this->advertisementFlagManager = $objectManager->getObject( - AdvertisementFlagManager::class, - [ - 'flagManager' => $this->flagManagerMock - ] - ); - } - - public function testSetNotifiedUser() - { - $userId = 1; - $this->flagManagerMock->expects($this->once()) - ->method('saveFlag') - ->with('advertisement_notification_seen_admin_' . $userId, 1) - ->willReturn(true); - $this->assertTrue($this->advertisementFlagManager->setNotifiedUser($userId)); - } - - public function testIsUserNotified() - { - $userId = 1; - $this->flagManagerMock->expects($this->once()) - ->method('getFlagData') - ->with('advertisement_notification_seen_admin_' . $userId) - ->willReturn(true); - $this->assertTrue($this->advertisementFlagManager->isUserNotified($userId)); - } -} diff --git a/app/code/Magento/Advertisement/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Advertisement/Test/Unit/Model/Condition/CanViewNotificationTest.php index 3fe6b6609bd5c..ecf283662959e 100644 --- a/app/code/Magento/Advertisement/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Advertisement/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -7,8 +7,10 @@ namespace Magento\Advertisement\Test\Unit\Model\Condition; use Magento\Advertisement\Model\Condition\CanViewNotification; +use Magento\Advertisement\Model\ResourceModel\Viewer\Logger; +use Magento\Advertisement\Model\Viewer\Log; +use Magento\Framework\App\ProductMetadataInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Advertisement\Model\AdvertisementFlagManager; use Magento\Backend\Model\Auth\Session; /** @@ -22,9 +24,14 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase private $canViewNotification; /** - * @var AdvertisementFlagManager|\PHPUnit_Framework_MockObject_MockObject + * @var Logger|\PHPUnit_Framework_MockObject_MockObject */ - private $advertisementFlagManagerMock; + private $viewerLoggerMock; + + /** + * @var ProductMetadataInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $productMetadataMock; /** * @var Session|\PHPUnit_Framework_MockObject_MockObject @@ -33,52 +40,72 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase public function setUp() { - $this->advertisementFlagManagerMock = $this->getMockBuilder(AdvertisementFlagManager::class) - ->disableOriginalConstructor() - ->getMock(); $this->sessionMock = $this->getMockBuilder(Session::class) ->disableOriginalConstructor() ->setMethods(['getUser', 'getId']) ->getMock(); + $this->viewerLoggerMock = $this->getMockBuilder(Logger::class) + ->disableOriginalConstructor() + ->getMock(); + $this->productMetadataMock = $this->getMockBuilder(ProductMetadataInterface::class) + ->disableOriginalConstructor() + ->getMock(); $objectManager = new ObjectManager($this); $this->canViewNotification = $objectManager->getObject( CanViewNotification::class, [ - 'advertisementFlagManager' => $this->advertisementFlagManagerMock, - 'session' => $this->sessionMock + 'viewerLogger' => $this->viewerLoggerMock, + 'session' => $this->sessionMock, + 'productMetadata' => $this->productMetadataMock, ] ); } - public function isVisibleProvider() - { - return [ - [1, false, true], - [1, true, false] - ]; - } - /** - * @dataProvider isVisibleProvider - * @param int $userId - * @param bool $isUserNotified * @param bool $expected + * @param string $variableName + * @param int $callNum + * @param string $version + * @param string $lastViewVersion + * @dataProvider isVisibleProvider */ - public function testIsVisible($userId, $isUserNotified, $expected) + public function testIsVisible($expected, $variableName, $callNum, $version, $lastViewVersion = null) { $this->sessionMock->expects($this->once()) ->method('getUser') ->willReturnSelf(); $this->sessionMock->expects($this->once()) ->method('getId') - ->willReturn($userId); - $this->advertisementFlagManagerMock->expects($this->once()) - ->method('isUserNotified') - ->willReturn($isUserNotified); - $this->advertisementFlagManagerMock->expects($this->any()) - ->method('setNotifiedUser') - ->willReturn(true); - + ->willReturn(1); + $this->productMetadataMock->expects($this->once()) + ->method('getVersion') + ->willReturn($version); + $viewerLogMock = $this->getMockBuilder(Log::class) + ->disableOriginalConstructor() + ->getMock(); + $viewerLogMock->expects($this->any()) + ->method('getLastViewVersion') + ->willReturn($lastViewVersion); + $viewerLogNull = null; + $this->viewerLoggerMock->expects($this->once()) + ->method('get') + ->with(1) + ->willReturn($$variableName); + $this->viewerLoggerMock->expects($this->exactly($callNum)) + ->method('log') + ->with(1, $version); $this->assertEquals($expected, $this->canViewNotification->isVisible([])); } + + public function isVisibleProvider() + { + return [ + [true, 'viewerLogNull', 1, '2.2.1-dev'], + [true, 'viewerLogMock', 1, '2.2.1-dev', null], + [true, 'viewerLogMock', 1, '2.2.1-dev', '2.2.1'], + [true, 'viewerLogMock', 1, '2.2.1-dev', '2.2.0'], + [true, 'viewerLogMock', 1, '2.3.0', '2.2.0'], + [false, 'viewerLogMock', 0, '2.2.2', '2.2.2'], + ]; + } } diff --git a/app/code/Magento/Advertisement/etc/module.xml b/app/code/Magento/Advertisement/etc/module.xml index 5db6c24c13cb6..fb3c9d0b05a79 100644 --- a/app/code/Magento/Advertisement/etc/module.xml +++ b/app/code/Magento/Advertisement/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/dev/tests/integration/testsuite/Magento/Advertisement/Model/ResourceModel/Viewer/LoggerTest.php b/dev/tests/integration/testsuite/Magento/Advertisement/Model/ResourceModel/Viewer/LoggerTest.php new file mode 100644 index 0000000000000..32cebc13dc39b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Advertisement/Model/ResourceModel/Viewer/LoggerTest.php @@ -0,0 +1,62 @@ +logger = $objectManager->get(Logger::class); + } + + /** + * @magentoDataFixture Magento/User/_files/user_with_role.php + */ + public function testLogAndGet() + { + $userModel = Bootstrap::getObjectManager()->get(\Magento\User\Model\User::class); + $adminUserNameFromFixture = 'adminUser'; + $adminUserId = $userModel->loadByUsername($adminUserNameFromFixture)->getId(); + $this->assertNull($this->logger->get($adminUserId)); + $firstLogVersion = '2.2.2'; + $this->logger->log($adminUserId, $firstLogVersion); + $firstLog = $this->logger->get($adminUserId); + $this->assertInstanceOf(Log::class, $firstLog); + $this->assertEquals($firstLogVersion, $firstLog->getLastViewVersion()); + $this->assertEquals($adminUserId, $firstLog->getViewerId()); + + $secondLogVersion = '2.3.0'; + $this->logger->log($adminUserId, $secondLogVersion); + $secondLog = $this->logger->get($adminUserId); + $this->assertInstanceOf(Log::class, $secondLog); + $this->assertEquals($secondLogVersion, $secondLog->getLastViewVersion()); + $this->assertEquals($adminUserId, $secondLog->getViewerId()); + $this->assertEquals($firstLog->getId(), $secondLog->getId()); + } + + /** + * @expectedException \Zend_Db_Statement_Exception + */ + public function testLogNonExistUser() + { + $this->logger->log(200, '2.2.2'); + } +} From 001df498846877a042cfddf0b565ae3e335e8766 Mon Sep 17 00:00:00 2001 From: Martin Peverelli Date: Fri, 20 Oct 2017 14:48:08 -0300 Subject: [PATCH 075/194] Fix Issue #7225 - Remove hardcoding of apply_to when saving attributes --- .../Catalog/Controller/Adminhtml/Product/Attribute/Save.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php index 8eb13af6f96f2..f2803c2399474 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php @@ -193,7 +193,7 @@ public function execute() ); } - $data += ['is_filterable' => 0, 'is_filterable_in_search' => 0, 'apply_to' => []]; + $data += ['is_filterable' => 0, 'is_filterable_in_search' => 0]; if (is_null($model->getIsUserDefined()) || $model->getIsUserDefined() != 0) { $data['backend_type'] = $model->getBackendTypeByInput($data['frontend_input']); From c630e4a7b7ba8cf2c638f50f2ec39304b6ee70f9 Mon Sep 17 00:00:00 2001 From: Pieter Cappelle Date: Fri, 20 Oct 2017 21:58:43 +0200 Subject: [PATCH 076/194] Fix issue 10032 --- .../Magento/Backup/Model/BackupFactory.php | 19 +++--- .../Test/Unit/Model/BackupFactoryTest.php | 59 ++++++++----------- 2 files changed, 31 insertions(+), 47 deletions(-) diff --git a/app/code/Magento/Backup/Model/BackupFactory.php b/app/code/Magento/Backup/Model/BackupFactory.php index c4e2be9758f72..28b0a7baf43cb 100644 --- a/app/code/Magento/Backup/Model/BackupFactory.php +++ b/app/code/Magento/Backup/Model/BackupFactory.php @@ -39,23 +39,20 @@ public function __construct(\Magento\Framework\ObjectManagerInterface $objectMan */ public function create($timestamp, $type) { - $backupId = $timestamp . '_' . $type; $fsCollection = $this->_objectManager->get(\Magento\Backup\Model\Fs\Collection::class); $backupInstance = $this->_objectManager->get(\Magento\Backup\Model\Backup::class); + foreach ($fsCollection as $backup) { - if ($backup->getId() == $backupId) { - $backupInstance->setType( - $backup->getType() - )->setTime( - $backup->getTime() - )->setName( - $backup->getName() - )->setPath( - $backup->getPath() - ); + if ($backup->getTime() === (int) $timestamp && $backup->getType() === $type) { + $backupInstance->setData(['id' => $backup->getId()]) + ->setType($backup->getType()) + ->setTime($backup->getTime()) + ->setName($backup->getName()) + ->setPath($backup->getPath()); break; } } + return $backupInstance; } } diff --git a/app/code/Magento/Backup/Test/Unit/Model/BackupFactoryTest.php b/app/code/Magento/Backup/Test/Unit/Model/BackupFactoryTest.php index dca65db48650f..629028bfd6f15 100644 --- a/app/code/Magento/Backup/Test/Unit/Model/BackupFactoryTest.php +++ b/app/code/Magento/Backup/Test/Unit/Model/BackupFactoryTest.php @@ -77,42 +77,29 @@ protected function setUp() public function testCreate() { - $this->_backupModel->expects( - $this->once() - )->method( - 'setType' - )->with( - $this->_data['type'] - )->will( - $this->returnSelf() - ); - $this->_backupModel->expects( - $this->once() - )->method( - 'setTime' - )->with( - $this->_data['time'] - )->will( - $this->returnSelf() - ); - $this->_backupModel->expects( - $this->once() - )->method( - 'setName' - )->with( - $this->_data['name'] - )->will( - $this->returnSelf() - ); - $this->_backupModel->expects( - $this->once() - )->method( - 'setPath' - )->with( - $this->_data['path'] - )->will( - $this->returnSelf() - ); + $this->_backupModel->expects($this->once()) + ->method('setType') + ->with($this->_data['type']) + ->will($this->returnSelf()); + + $this->_backupModel->expects($this->once()) + ->method('setTime') + ->with($this->_data['time']) + ->will($this->returnSelf()); + + $this->_backupModel->expects($this->once()) + ->method('setName') + ->with($this->_data['name']) + ->will($this->returnSelf()); + + $this->_backupModel->expects($this->once()) + ->method('setPath') + ->with($this->_data['path']) + ->will($this->returnSelf()); + + $this->_backupModel->expects($this->once()) + ->method('setData') + ->will($this->returnSelf()); $this->_instance->create('1385661590', 'snapshot'); } From f686c4d4bd9804c0c11626b6b6cf8a157fb4a8f4 Mon Sep 17 00:00:00 2001 From: Joan He Date: Fri, 20 Oct 2017 15:24:15 -0500 Subject: [PATCH 077/194] MAGETWO-82125: Display advertisement popup at the 1st time per admin login --- .../Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php b/app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php index a38b888de4d64..3f757b865c9a7 100644 --- a/app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php +++ b/app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php @@ -54,7 +54,7 @@ public function log($viewerId, $lastViewVersion) $connection = $this->resource->getConnection(ResourceConnection::DEFAULT_CONNECTION); $connection->insertOnDuplicate( - $this->resource->getTableName(self::TABLE_NAME ), + $this->resource->getTableName(self::TABLE_NAME), [ 'viewer_id' => $viewerId, 'last_view_version' => $lastViewVersion From 70d7502aed7e6d9332399e7c38aa0e971d882b9a Mon Sep 17 00:00:00 2001 From: Marc Rodriguez Date: Sat, 21 Oct 2017 10:17:58 +0200 Subject: [PATCH 078/194] FR#6891_22 Add-to-cart checkbox still visible when = false --- .../Catalog/view/frontend/templates/product/list/items.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/list/items.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/list/items.phtml index 1b9f014b7c27f..fc0967ca60d2d 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/list/items.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/list/items.phtml @@ -203,7 +203,7 @@ switch ($type = $block->getType()) { getReviewsSummaryHtml($_item, $templateType) ?> - isComposite() && $_item->isSaleable() && $type == 'related'): ?> + isComposite() && $_item->isSaleable() && $type == 'related'): ?> getRequiredOptions()): ?>