diff --git a/CHANGELOG.md b/CHANGELOG.md index 44844f62b6449..bc8186b776232 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,81 @@ +2.1.13 +============= +* GitHub issues: + * [#9869](https://github.com/magento/magento2/issues/9869) -- datetime type product attribute showing current date (fixed in [magento/magento2#12033](https://github.com/magento/magento2/pull/12033)) + * [#10765](https://github.com/magento/magento2/issues/10765) -- Export data from grid not adding custom rendered data magento2 (fixed in [magento/magento2#12373](https://github.com/magento/magento2/pull/12373)) + * [#9410](https://github.com/magento/magento2/issues/9410) -- Impossible to add swatch options via Service Contracts if there is no existing swatch option for attribute (fixed in [magento/magento2#12043](https://github.com/magento/magento2/pull/12043)) + * [#10707](https://github.com/magento/magento2/issues/10707) -- Create attribute option via API for swatch attribute fails (fixed in [magento/magento2#12043](https://github.com/magento/magento2/pull/12043)) + * [#10737](https://github.com/magento/magento2/issues/10737) -- Can't import attribute option over API if option is 'visual swatch' (fixed in [magento/magento2#12043](https://github.com/magento/magento2/pull/12043)) + * [#11032](https://github.com/magento/magento2/issues/11032) -- Unable to add new options to swatch attribute (fixed in [magento/magento2#12043](https://github.com/magento/magento2/pull/12043)) + * [#10210](https://github.com/magento/magento2/issues/10210) -- Transport variable can not be altered in email_invoice_set_template_vars_before Event (fixed in [magento/magento2#12135](https://github.com/magento/magento2/pull/12135)) + * [#11341](https://github.com/magento/magento2/issues/11341) -- Attribute category_ids issue (fixed in [magento/magento2#11807](https://github.com/magento/magento2/pull/11807)) + * [#11825](https://github.com/magento/magento2/issues/11825) -- 2.1.9 Item not added to the Wishlist if the user is not logged at the moment he click on the button to add it. (fixed in [magento/magento2#12041](https://github.com/magento/magento2/pull/12041)) + * [#11908](https://github.com/magento/magento2/issues/11908) -- Adding to wishlist doesn't work when not logged in (fixed in [magento/magento2#12041](https://github.com/magento/magento2/pull/12041)) + * [#9768](https://github.com/magento/magento2/issues/9768) -- Admin dashboard Most Viewed Products Tab only gives default attribute set's products (fixed in [magento/magento2#12137](https://github.com/magento/magento2/pull/12137)) + * [#11409](https://github.com/magento/magento2/issues/11409) -- Too many password reset requests even when disabled in settings (fixed in [magento/magento2#11436](https://github.com/magento/magento2/pull/11436)) + * [#8009](https://github.com/magento/magento2/issues/8009) -- Magento 2.1.3 out of stock associated products to configurable are not full page cache cleaned (fixed in [magento/magento2#12548](https://github.com/magento/magento2/pull/12548)) + * [#12268](https://github.com/magento/magento2/issues/12268) -- Gallery issues on configurable product page (fixed in [magento/magento2#12558](https://github.com/magento/magento2/pull/12558)) + * [#8069](https://github.com/magento/magento2/issues/8069) -- Saving Category with existing image causes an exception (fixed in [magento/magento2#12368](https://github.com/magento/magento2/pull/12368)) + * [#6770](https://github.com/magento/magento2/issues/6770) -- M2.1.1 : Re-saving a product attribute with a different name than it's code results in an error (fixed in [magento/magento2#11618](https://github.com/magento/magento2/pull/11618)) + * [#12627](https://github.com/magento/magento2/issues/12627) -- Referer is not added to login url in checkout config (fixed in [magento/magento2#12629](https://github.com/magento/magento2/pull/12629)) + * [#8415](https://github.com/magento/magento2/issues/8415) -- Content Block Administration fails when I delete more than one record (fixed in [magento/magento2#12840](https://github.com/magento/magento2/pull/12840)) + * [#9243](https://github.com/magento/magento2/issues/9243) -- Upgrade ZF components. Zend_Service (fixed in [magento/magento2#12958](https://github.com/magento/magento2/pull/12958)) + * [#10812](https://github.com/magento/magento2/issues/10812) -- htaccess Options override (fixed in [magento/magento2#12959](https://github.com/magento/magento2/pull/12959)) + * [#7441](https://github.com/magento/magento2/issues/7441) -- Configurable attribute options are not sorted (fixed in [magento/magento2#12962](https://github.com/magento/magento2/pull/12962)) + * [#10682](https://github.com/magento/magento2/issues/10682) -- Meta description and keywords transform to html entities for non latin/cyrilic characters in category and product pages (fixed in [magento/magento2#12956](https://github.com/magento/magento2/pull/12956)) + * [#9969](https://github.com/magento/magento2/issues/9969) -- Cancel order and restore quote methods increase stocks twice (fixed in [magento/magento2#12952](https://github.com/magento/magento2/pull/12952)) + * [#2156](https://github.com/magento/magento2/issues/2156) -- Why does \Magento\Translation\Model\Js\DataProvider use \Magento\Framework\Phrase\Renderer\Translate, not \Magento\Framework\Phrase\Renderer\Composite? (fixed in [magento/magento2#12954](https://github.com/magento/magento2/pull/12954)) + * [#12967](https://github.com/magento/magento2/issues/12967) -- Undeclared dependency magento/zendframework1 by magento/framework (fixed in [magento/magento2#12991](https://github.com/magento/magento2/pull/12991)) + * [#12393](https://github.com/magento/magento2/issues/12393) -- Attribute with "Catalog Input Type for Store Owner" equal "Fixed Product Tax" for Multi-store (fixed in [magento/magento2#13020](https://github.com/magento/magento2/pull/13020)) + * [#10168](https://github.com/magento/magento2/issues/10168) -- Coupon codes not showing in invoice (fixed in [magento/magento2#13261](https://github.com/magento/magento2/pull/13261)) + * [#8621](https://github.com/magento/magento2/issues/8621) -- M2.1 Multishipping Checkout step New Address - Old State is saved when country is changed (fixed in [magento/magento2#13367](https://github.com/magento/magento2/pull/13367)) + * [#10738](https://github.com/magento/magento2/issues/10738) -- Empty attribute label is displayed on product page when other language used. (fixed in [magento/magento2#13532](https://github.com/magento/magento2/pull/13532)) + * [#6207](https://github.com/magento/magento2/issues/6207) -- Checkbox IDs for Terms and Conditions should be unique in Checkout (fixed in [magento/magento2#13543](https://github.com/magento/magento2/pull/13543)) + * [#10565](https://github.com/magento/magento2/issues/10565) -- Magento ver. 2.1.8 New Product with Custom attribute set not working (fixed in [magento/magento2#13549](https://github.com/magento/magento2/pull/13549)) + * [#6457](https://github.com/magento/magento2/issues/6457) -- Expired special_price is still shown for configurable products when no variant is selected (fixed in [magento/magento2#13490](https://github.com/magento/magento2/pull/13490)) + * [#6729](https://github.com/magento/magento2/issues/6729) -- Configurable product old price with taxes displayed wrong (fixed in [magento/magento2#13490](https://github.com/magento/magento2/pull/13490)) + * [#7362](https://github.com/magento/magento2/issues/7362) -- Special price vigency for configurable childs (simple products associated) doesn´t work (fixed in [magento/magento2#13490](https://github.com/magento/magento2/pull/13490)) +* GitHub pull requests: + * [magento/magento2#12033](https://github.com/magento/magento2/pull/12033) -- Backport 2.1-develop] Fix datetime type product that show current date when is empty in grids (by @enriquei4) + * [magento/magento2#12373](https://github.com/magento/magento2/pull/12373) -- #10765 Export data from grid not adding custom rendered data magento2 (by @Zefiryn) + * [magento/magento2#12043](https://github.com/magento/magento2/pull/12043) -- [Backport 2.1] Add swatch option: Prevent loosing data and default value if data is not populated via adminhtml (by @gomencal) + * [magento/magento2#12135](https://github.com/magento/magento2/pull/12135) -- 10210: Transport variable can not be altered in email_invoice_set_template_vars_before Event (backport MAGETWO-69482 to 2.1). (by @RomaKis) + * [magento/magento2#11807](https://github.com/magento/magento2/pull/11807) -- [backport 2.1] Attribute category_ids issue #11389 (by @manuelson) + * [magento/magento2#12246](https://github.com/magento/magento2/pull/12246) -- Clear `mage-cache-sessid` cookie on Ajax Login (by @pmclain) + * [magento/magento2#12041](https://github.com/magento/magento2/pull/12041) -- [Backport 2.1] #11825: Generate new FormKey and replace for oldRequestParams Wishlist (by @osrecio) + * [magento/magento2#12137](https://github.com/magento/magento2/pull/12137) -- 9768: Admin dashboard Most Viewed Products Tab only gives default attribute set's products (backport for 2.1) (by @RomaKis) + * [magento/magento2#12519](https://github.com/magento/magento2/pull/12519) -- Duplicate array key (by @lfluvisotto) + * [magento/magento2#11860](https://github.com/magento/magento2/pull/11860) -- [Backport 2.1-develop] CMS Page - Force validate layout update xml in production mode when saving CMS Page - Handle layout update xml validation exceptions (by @adrian-martinez-interactiv4) + * [magento/magento2#12522](https://github.com/magento/magento2/pull/12522) -- PR#12466 [BACKPORT 2.1] (by @atishgoswami) + * [magento/magento2#12321](https://github.com/magento/magento2/pull/12321) -- Trying to get data from non existent products (by @angelo983) + * [magento/magento2#11436](https://github.com/magento/magento2/pull/11436) -- [Backport 2.1-develop] #11409: Too many password reset requests even when disabled in settings (by @adrian-martinez-interactiv4) + * [magento/magento2#12548](https://github.com/magento/magento2/pull/12548) -- Fixes #8009 (by @ajpevers) + * [magento/magento2#12050](https://github.com/magento/magento2/pull/12050) -- [2.1] - Add command to view mview state and queue (by @convenient) + * [magento/magento2#12558](https://github.com/magento/magento2/pull/12558) -- [Backport-2.1] Added namespace to product videos fotorama events (by @roma84) + * [magento/magento2#12579](https://github.com/magento/magento2/pull/12579) -- [Backport 2.1-develop] Fix swagger-ui on instances of Magento running on a non-standard port (by @JeroenVanLeusden) + * [magento/magento2#12368](https://github.com/magento/magento2/pull/12368) -- [Backport for 2.1 of #9904] #8069: Saving Category with existing imag… (by @nemesis-back) + * [magento/magento2#11618](https://github.com/magento/magento2/pull/11618) -- Re saving product attribute [backport 2.1] (by @raumatbel) + * [magento/magento2#12611](https://github.com/magento/magento2/pull/12611) -- Backport #4958 to 2.1 (by @slackerzz) + * [magento/magento2#12629](https://github.com/magento/magento2/pull/12629) -- [2.1-develop] Add customer login url from Customer Url model to checkout config so … (by @quisse) + * [magento/magento2#12840](https://github.com/magento/magento2/pull/12840) -- Backport PR8418 - Fatal error on cms block grid delete (by @duckchip) + * [magento/magento2#12930](https://github.com/magento/magento2/pull/12930) -- Fix wishlist item getBuyRequest with no options (by @jameshalsall) + * [magento/magento2#12959](https://github.com/magento/magento2/pull/12959) -- [Backport to 2.1-develop] Fix #10812: htaccess Options override (by @dverkade) + * [magento/magento2#12958](https://github.com/magento/magento2/pull/12958) -- [Backport to 2.1-develop] Fix #9243 - Upgrade ZF components. Zend_Service (by @dverkade) + * [magento/magento2#12956](https://github.com/magento/magento2/pull/12956) -- [Backport to 2.1-develop] Fix #10682: Meta description and keywords transform to html entities (by @dverkade) + * [magento/magento2#12962](https://github.com/magento/magento2/pull/12962) -- [Backport to 2.1-develop] Fix configurable attribute options not being sorted (by @wardcapp) + * [magento/magento2#12952](https://github.com/magento/magento2/pull/12952) -- [Backport #12668 into 2.1-develop] Fix for reverting stock twice for cancelled orders (by @dverkade) + * [magento/magento2#12954](https://github.com/magento/magento2/pull/12954) -- [Backport to 2.1-develop] Fix #2156 Js\Dataprovider uses the RendererInterface. (by @dverkade) + * [magento/magento2#12991](https://github.com/magento/magento2/pull/12991) -- [2.1.x] Fix undeclared dependency magento/zendframework1 by magento/framework (by @ihor-sviziev) + * [magento/magento2#13020](https://github.com/magento/magento2/pull/13020) -- [Backport to 2.1-develop] Attribute with "Catalog Input Type for Store Owner" equal "Fixed Product Tax" for Multi-store (by @dverkade) + * [magento/magento2#13261](https://github.com/magento/magento2/pull/13261) -- Backport 2.1 for MAGETWO-80428 (by @PieterCappelle) + * [magento/magento2#13367](https://github.com/magento/magento2/pull/13367) -- [Backport 2.1] In checkout->multishipping-> new addres clean region when select country without dropdown for states (by @enriquei4) + * [magento/magento2#13489](https://github.com/magento/magento2/pull/13489) -- [Backport 2.1] #9247 fixed layout handle for cms page (by @simpleadm) + * [magento/magento2#13532](https://github.com/magento/magento2/pull/13532) -- Backport of PR-11169 for Magento 2.1: Fixed issue #10738: Empty attribute label is displayed on product pag… (by @hostep) + * [magento/magento2#13543](https://github.com/magento/magento2/pull/13543) -- Backport of MAGETWO-69379 for Magento 2.1: use payment method name to… (by @hostep) + * [magento/magento2#13549](https://github.com/magento/magento2/pull/13549) -- Backport of MAGETWO-80198 for Magento 2.1: Fix issue #10565 #10575 (by @hostep) + * [magento/magento2#13490](https://github.com/magento/magento2/pull/13490) -- [Backport 2.1] #9796 configurable product price options provider (by @simpleadm) + * [magento/magento2#13916](https://github.com/magento/magento2/pull/13916) -- Pass Expected Data Type in backgroundColor Call (2.1) (by @northernco) + 2.1.11 ============= * GitHub issues: diff --git a/README.md b/README.md index 74f3a517570d0..aa83b880ca38d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ -[![Build Status](https://travis-ci.org/magento/magento2.svg?branch=develop)](https://travis-ci.org/magento/magento2) +[![Build Status](https://travis-ci.org/magento/magento2.svg?branch=2.1-develop)](https://travis-ci.org/magento/magento2) +[![Open Source Helpers](https://www.codetriage.com/magento/magento2/badges/users.svg)](https://www.codetriage.com/magento/magento2) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/magento/magento2?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)

Welcome

-Welcome to Magento 2 installation! We're glad you chose to install Magento 2, a cutting edge, feature-rich eCommerce solution that gets results. +Welcome to Magento 2 installation! We're glad you chose to install Magento 2, a cutting-edge, feature-rich eCommerce solution that gets results. The installation instructions that used to be here are now published on our GitHub site. Use the information on this page to get started or go directly to the guide. @@ -73,6 +74,19 @@ To suggest documentation improvements, click [here][4]. [3]: [4]: +

Community Maintainers

+The members of this team have been recognized for their outstanding commitment to maintaining and improving Magento. Magento has granted them permission to accept, merge, and reject pull requests, as well as review issues, and thanks these Community Maintainers for their valuable contributions. + + + + + +

Top Contributors

+Magento is thankful for any contribution that can improve our code base, documentation or increase test coverage. We always recognize our most active members, as their contributions are the foundation of the Magento Open Source platform. + + + +

Reporting security issues

To report security vulnerabilities in Magento software or web sites, please e-mail security@magento.com. Please do not report security issues using GitHub. Be sure to encrypt your e-mail with our encryption key if it includes sensitive information. Learn more about reporting security issues here. diff --git a/app/code/Magento/AdminNotification/Controller/Adminhtml/System/Message/ListAction.php b/app/code/Magento/AdminNotification/Controller/Adminhtml/System/Message/ListAction.php index 68de06c1c22bd..f74a2907b318f 100644 --- a/app/code/Magento/AdminNotification/Controller/Adminhtml/System/Message/ListAction.php +++ b/app/code/Magento/AdminNotification/Controller/Adminhtml/System/Message/ListAction.php @@ -61,8 +61,10 @@ public function execute() if (empty($result)) { $result[] = [ 'severity' => (string)\Magento\Framework\Notification\MessageInterface::SEVERITY_NOTICE, - 'text' => 'You have viewed and resolved all recent system notices. ' - . 'Please refresh the web page to clear the notice alert.', + 'text' => __( + 'You have viewed and resolved all recent system notices. ' + . 'Please refresh the web page to clear the notice alert.' + ) ]; } $this->getResponse()->representJson($this->jsonHelper->jsonEncode($result)); diff --git a/app/code/Magento/AdminNotification/composer.json b/app/code/Magento/AdminNotification/composer.json index cc0f1d9c5abbb..ca1ca07d44a50 100644 --- a/app/code/Magento/AdminNotification/composer.json +++ b/app/code/Magento/AdminNotification/composer.json @@ -10,7 +10,7 @@ "lib-libxml": "*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/AdminNotification/i18n/en_US.csv b/app/code/Magento/AdminNotification/i18n/en_US.csv index 7b55e96976cad..8f780efa6c184 100644 --- a/app/code/Magento/AdminNotification/i18n/en_US.csv +++ b/app/code/Magento/AdminNotification/i18n/en_US.csv @@ -49,3 +49,4 @@ Severity,Severity "Date Added","Date Added" Message,Message Actions,Actions +"You have viewed and resolved all recent system notices. Please refresh the web page to clear the notice alert.","You have viewed and resolved all recent system notices. Please refresh the web page to clear the notice alert." diff --git a/app/code/Magento/AdvancedPricingImportExport/composer.json b/app/code/Magento/AdvancedPricingImportExport/composer.json index b52a4b8c3e532..19d3a4e96f82f 100644 --- a/app/code/Magento/AdvancedPricingImportExport/composer.json +++ b/app/code/Magento/AdvancedPricingImportExport/composer.json @@ -13,7 +13,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Authorization/composer.json b/app/code/Magento/Authorization/composer.json index 0d50099d2e79f..5a19aeabb8b9b 100644 --- a/app/code/Magento/Authorization/composer.json +++ b/app/code/Magento/Authorization/composer.json @@ -7,7 +7,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.2", + "version": "100.1.3", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Authorizenet/composer.json b/app/code/Magento/Authorizenet/composer.json index 27c012020c1e6..d127e7527e21c 100644 --- a/app/code/Magento/Authorizenet/composer.json +++ b/app/code/Magento/Authorizenet/composer.json @@ -13,7 +13,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.6", + "version": "100.1.7", "license": [ "proprietary" ], diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Date.php b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Date.php index 5c50771a9cbf8..24c7627ce14ea 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Date.php +++ b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Date.php @@ -125,7 +125,7 @@ public function getHtml() /** * @param string|null $index - * @return string + * @return array|string|int|float|null */ public function getEscapedValue($index = null) { @@ -136,6 +136,11 @@ public function getEscapedValue($index = null) $this->_localeDate->getDateFormat(\IntlDateFormatter::SHORT) ); } + + if (is_string($value)) { + return $this->escapeHtml($value); + } + return $value; } diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Datetime.php b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Datetime.php index 9f2ce62ecf96c..13d5de1f3fc85 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Datetime.php +++ b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Datetime.php @@ -142,8 +142,8 @@ public function getHtml() /** * Return escaped value for calendar * - * @param string $index - * @return string + * @param string|null $index + * @return array|string|int|float|null */ public function getEscapedValue($index = null) { @@ -152,6 +152,11 @@ public function getEscapedValue($index = null) if ($value instanceof \DateTime) { return $this->_localeDate->formatDateTime($value); } + + if (is_string($value)) { + return $this->escapeHtml($value); + } + return $value; } diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Radio.php b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Radio.php index 2cbe264c5f396..479a2b6b20293 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Radio.php +++ b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Radio.php @@ -31,8 +31,7 @@ public function getCondition() { if ($this->getValue()) { return $this->getColumn()->getValue(); - } else { - return [['neq' => $this->getColumn()->getValue()], ['is' => new \Zend_Db_Expr('NULL')]]; } + return [['neq' => $this->getColumn()->getValue()], ['is' => new \Zend_Db_Expr('NULL')]]; } } diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php index 9ff5b4cab1953..d40e77f7f0580 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php +++ b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php @@ -205,9 +205,8 @@ public function getSelectedJson() if ($selected = $this->getRequest()->getParam($this->getFormFieldNameInternal())) { $selected = explode(',', $selected); return join(',', $selected); - } else { - return ''; } + return ''; } /** @@ -220,9 +219,8 @@ public function getSelected() if ($selected = $this->getRequest()->getParam($this->getFormFieldNameInternal())) { $selected = explode(',', $selected); return $selected; - } else { - return []; } + return []; } /** diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Massaction/Extended.php b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/Extended.php index e4590410fc1e5..378368d9b92df 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid/Massaction/Extended.php +++ b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/Extended.php @@ -215,9 +215,8 @@ public function getSelectedJson() if ($selected = $this->getRequest()->getParam($this->getFormFieldNameInternal())) { $selected = explode(',', $selected); return join(',', $selected); - } else { - return ''; } + return ''; } /** @@ -230,9 +229,8 @@ public function getSelected() if ($selected = $this->getRequest()->getParam($this->getFormFieldNameInternal())) { $selected = explode(',', $selected); return $selected; - } else { - return []; } + return []; } /** diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Auth/Login.php b/app/code/Magento/Backend/Controller/Adminhtml/Auth/Login.php index 8b934e6760f63..588f3d1a8b827 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/Auth/Login.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/Auth/Login.php @@ -46,9 +46,8 @@ public function execute() // redirect according to rewrite rule if ($requestUrl != $backendUrl) { return $this->getRedirect($backendUrl); - } else { - return $this->resultPageFactory->create(); } + return $this->resultPageFactory->create(); } /** diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Save.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Save.php index 3ff6ab635e2bc..ac73d3629083a 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Save.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Save.php @@ -29,9 +29,8 @@ private function getSecurityCookie() { if (!($this->securityCookie instanceof SecurityCookie)) { return \Magento\Framework\App\ObjectManager::getInstance()->get(SecurityCookie::class); - } else { - return $this->securityCookie; } + return $this->securityCookie; } /** diff --git a/app/code/Magento/Backend/Model/Url.php b/app/code/Magento/Backend/Model/Url.php index 764ab297605d5..e91344f341269 100644 --- a/app/code/Magento/Backend/Model/Url.php +++ b/app/code/Magento/Backend/Model/Url.php @@ -198,7 +198,9 @@ public function getUrl($routePath = null, $routeParams = null) return $result; } + $this->getRouteParamsResolver()->unsetData('route_params'); $this->_setRoutePath($routePath); + $extraParams = $this->getRouteParamsResolver()->getRouteParams(); $routeName = $this->_getRouteName('*'); $controllerName = $this->_getControllerName(self::DEFAULT_CONTROLLER_NAME); $actionName = $this->_getActionName(self::DEFAULT_ACTION_NAME); @@ -213,6 +215,10 @@ public function getUrl($routePath = null, $routeParams = null) $routeParams[self::SECRET_KEY_PARAM_NAME] = $secretKey; } + if (!empty($extraParams)) { + $routeParams = array_merge($extraParams, $routeParams); + } + return parent::getUrl("{$routeName}/{$controllerName}/{$actionName}", $routeParams); } diff --git a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DateTest.php b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DateTest.php index 5ec0324fa6afb..593a3ed29f676 100644 --- a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DateTest.php +++ b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DateTest.php @@ -32,35 +32,35 @@ class DateTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->mathRandomMock = $this->getMockBuilder('Magento\Framework\Math\Random') + $this->mathRandomMock = $this->getMockBuilder(\Magento\Framework\Math\Random::class) ->disableOriginalConstructor() ->setMethods(['getUniqueHash']) ->getMock(); - $this->localeResolverMock = $this->getMockBuilder('Magento\Framework\Locale\ResolverInterface') + $this->localeResolverMock = $this->getMockBuilder(\Magento\Framework\Locale\ResolverInterface::class) ->disableOriginalConstructor() ->setMethods([]) ->getMock(); $this->dateTimeFormatterMock = $this - ->getMockBuilder('Magento\Framework\Stdlib\DateTime\DateTimeFormatterInterface') + ->getMockBuilder(\Magento\Framework\Stdlib\DateTime\DateTimeFormatterInterface::class) ->disableOriginalConstructor() ->setMethods([]) ->getMock(); - $this->columnMock = $this->getMockBuilder('Magento\Backend\Block\Widget\Grid\Column') + $this->columnMock = $this->getMockBuilder(\Magento\Backend\Block\Widget\Grid\Column::class) ->disableOriginalConstructor() ->setMethods(['getTimezone', 'getHtmlId', 'getId']) ->getMock(); - $this->localeDateMock = $this->getMockBuilder('\Magento\Framework\Stdlib\DateTime\TimezoneInterface') + $this->localeDateMock = $this->getMockBuilder(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class) ->disableOriginalConstructor() ->setMethods([]) ->getMock(); $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->model = $objectManagerHelper->getObject( - 'Magento\Backend\Block\Widget\Grid\Column\Filter\Date', + \Magento\Backend\Block\Widget\Grid\Column\Filter\Date::class, [ 'mathRandom' => $this->mathRandomMock, 'localeResolver' => $this->localeResolverMock, diff --git a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DatetimeTest.php b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DatetimeTest.php index 7d41eb579f2bb..e648a1fa0673f 100644 --- a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DatetimeTest.php +++ b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DatetimeTest.php @@ -32,35 +32,35 @@ class DatetimeTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->mathRandomMock = $this->getMockBuilder('Magento\Framework\Math\Random') + $this->mathRandomMock = $this->getMockBuilder(\Magento\Framework\Math\Random::class) ->disableOriginalConstructor() ->setMethods(['getUniqueHash']) ->getMock(); - $this->localeResolverMock = $this->getMockBuilder('Magento\Framework\Locale\ResolverInterface') + $this->localeResolverMock = $this->getMockBuilder(\Magento\Framework\Locale\ResolverInterface::class) ->disableOriginalConstructor() ->setMethods([]) ->getMock(); $this->dateTimeFormatterMock = $this - ->getMockBuilder('Magento\Framework\Stdlib\DateTime\DateTimeFormatterInterface') + ->getMockBuilder(\Magento\Framework\Stdlib\DateTime\DateTimeFormatterInterface::class) ->disableOriginalConstructor() ->setMethods([]) ->getMock(); - $this->columnMock = $this->getMockBuilder('Magento\Backend\Block\Widget\Grid\Column') + $this->columnMock = $this->getMockBuilder(\Magento\Backend\Block\Widget\Grid\Column::class) ->disableOriginalConstructor() ->setMethods(['getTimezone', 'getHtmlId', 'getId']) ->getMock(); - $this->localeDateMock = $this->getMockBuilder('\Magento\Framework\Stdlib\DateTime\TimezoneInterface') + $this->localeDateMock = $this->getMockBuilder(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class) ->disableOriginalConstructor() ->setMethods([]) ->getMock(); $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->model = $objectManagerHelper->getObject( - 'Magento\Backend\Block\Widget\Grid\Column\Filter\Datetime', + \Magento\Backend\Block\Widget\Grid\Column\Filter\Datetime::class, [ 'mathRandom' => $this->mathRandomMock, 'localeResolver' => $this->localeResolverMock, diff --git a/app/code/Magento/Backend/composer.json b/app/code/Magento/Backend/composer.json index 6df4b1c555a74..ffbe1007d3a35 100644 --- a/app/code/Magento/Backend/composer.json +++ b/app/code/Magento/Backend/composer.json @@ -22,7 +22,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.6", + "version": "100.1.8", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Backend/etc/adminhtml/system.xml b/app/code/Magento/Backend/etc/adminhtml/system.xml index c038c58369c00..8bc52141872ca 100644 --- a/app/code/Magento/Backend/etc/adminhtml/system.xml +++ b/app/code/Magento/Backend/etc/adminhtml/system.xml @@ -116,7 +116,7 @@ Magento\Config\Model\Config\Source\Yesno - + Magento\Config\Model\Config\Source\Yesno @@ -405,7 +405,7 @@ general Magento_Backend::web - + @@ -415,7 +415,7 @@ Warning! When using Store Code in URLs, in some cases system may not work properly if URLs without Store Codes are specified in the third party services (e.g. PayPal etc.).]]> - + Magento\Config\Model\Config\Source\Web\Redirect I.e. redirect from http://example.com/store/ to http://www.example.com/store/ diff --git a/app/code/Magento/Backend/i18n/en_US.csv b/app/code/Magento/Backend/i18n/en_US.csv index 08a28eb95579b..d34827b14e520 100644 --- a/app/code/Magento/Backend/i18n/en_US.csv +++ b/app/code/Magento/Backend/i18n/en_US.csv @@ -324,7 +324,7 @@ Developer,Developer Debug,Debug "Enabled Template Path Hints for Storefront","Enabled Template Path Hints for Storefront" "Enabled Template Path Hints for Admin","Enabled Template Path Hints for Admin" -"Add Block Names to Hints","Add Block Names to Hints" +"Add Block Class Type to Hints","Add Block Class Type to Hints" "Template Settings","Template Settings" "Allow Symlinks","Allow Symlinks" "Warning! Enabling this feature is not recommended on production environments because it represents a potential security risk.","Warning! Enabling this feature is not recommended on production environments because it represents a potential security risk." diff --git a/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/grid.html b/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/grid.html index 40a275ed6a98e..0b785aa9984aa 100644 --- a/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/grid.html +++ b/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/grid.html @@ -85,7 +85,7 @@
+ translate="'Search strings are either normal strings or regular expressions (PCRE). They are matched in the same order as entered.'">
: diff --git a/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php b/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php index 6086a64bff8ad..0bd7ef3d82ade 100644 --- a/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php +++ b/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php @@ -12,14 +12,14 @@ class Create extends \Magento\Backup\Controller\Adminhtml\Index { /** - * Create backup action + * Create backup action. * * @return void|\Magento\Backend\App\Action * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function execute() { - if (!$this->getRequest()->isAjax()) { + if (!$this->requestAllowed()) { return $this->_redirect('*/*/index'); } @@ -28,7 +28,7 @@ public function execute() /** * @var \Magento\Backup\Helper\Data $helper */ - $helper = $this->_objectManager->get('Magento\Backup\Helper\Data'); + $helper = $this->_objectManager->get(\Magento\Backup\Helper\Data::class); try { $type = $this->getRequest()->getParam('type'); @@ -73,7 +73,7 @@ public function execute() if ($type != \Magento\Framework\Backup\Factory::TYPE_DB) { /** @var Filesystem $filesystem */ - $filesystem = $this->_objectManager->get('Magento\Framework\Filesystem'); + $filesystem = $this->_objectManager->get(\Magento\Framework\Filesystem::class); $backupManager->setRootDir($filesystem->getDirectoryRead(DirectoryList::ROOT)->getAbsolutePath()) ->addIgnorePaths($helper->getBackupIgnorePaths()); } @@ -88,10 +88,10 @@ public function execute() } catch (\Magento\Framework\Backup\Exception\NotEnoughFreeSpace $e) { $errorMessage = __('You need more free space to create a backup.'); } catch (\Magento\Framework\Backup\Exception\NotEnoughPermissions $e) { - $this->_objectManager->get('Psr\Log\LoggerInterface')->info($e->getMessage()); + $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->info($e->getMessage()); $errorMessage = __('You need more permissions to create a backup.'); } catch (\Exception $e) { - $this->_objectManager->get('Psr\Log\LoggerInterface')->info($e->getMessage()); + $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->info($e->getMessage()); $errorMessage = __('We can\'t create the backup right now.'); } @@ -106,4 +106,14 @@ public function execute() $this->getResponse()->representJson($response->toJson()); } + + /** + * Check if request is allowed. + * + * @return bool + */ + private function requestAllowed() + { + return $this->getRequest()->isAjax() && $this->getRequest()->isPost(); + } } diff --git a/app/code/Magento/Backup/Test/Unit/Controller/Adminhtml/Index/CreateTest.php b/app/code/Magento/Backup/Test/Unit/Controller/Adminhtml/Index/CreateTest.php new file mode 100644 index 0000000000000..7c4b963089139 --- /dev/null +++ b/app/code/Magento/Backup/Test/Unit/Controller/Adminhtml/Index/CreateTest.php @@ -0,0 +1,244 @@ +objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManagerInterface::class) + ->getMock(); + $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) + ->disableOriginalConstructor() + ->setMethods(['isAjax', 'isPost', 'getParam']) + ->getMock(); + $this->responseMock = $this->getMockBuilder(\Magento\Framework\App\Response\Http::class) + ->disableOriginalConstructor() + ->setMethods(['representJson']) + ->getMock(); + $this->sessionMock = $this->getMockBuilder(\Magento\Backend\Model\Session::class) + ->disableOriginalConstructor() + ->getMock(); + $this->backupFactoryMock = $this->getMockBuilder(\Magento\Framework\Backup\Factory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->backupModelMock = $this->getMockBuilder(\Magento\Backup\Model\Backup::class) + ->disableOriginalConstructor() + ->setMethods(['setBackupExtension', 'setTime', 'setBackupsDir', 'setName', 'create']) + ->getMock(); + $this->dataBackendHelperMock = $this->getMockBuilder(\Magento\Backend\Helper\Data::class) + ->disableOriginalConstructor() + ->setMethods(['getUrl']) + ->getMock(); + $this->dataBackupHelperMock = $this->getMockBuilder(\Magento\Backup\Helper\Data::class) + ->disableOriginalConstructor() + ->setMethods(['getExtensionByType', 'getBackupsDir']) + ->getMock(); + $this->maintenanceMode = $this->getMockBuilder(\Magento\Framework\App\MaintenanceMode::class) + ->disableOriginalConstructor() + ->setMethods(['set']) + ->getMock(); + $this->fileFactoryMock = $this->getMockBuilder(\Magento\Framework\App\Response\Http\FileFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->objectManager = new ObjectManager($this); + $this->context = $this->objectManager->getObject( + \Magento\Backend\App\Action\Context::class, + [ + 'objectManager' => $this->objectManagerMock, + 'request' => $this->requestMock, + 'response' => $this->responseMock, + 'session' => $this->sessionMock, + 'helper' => $this->dataBackendHelperMock, + 'maintenanceMode' => $this->maintenanceMode, + ] + ); + $this->createController = $this->objectManager->getObject( + \Magento\Backup\Controller\Adminhtml\Index\Create::class, + [ + 'context' => $this->context, + 'backupFactory' => $this->backupFactoryMock, + 'fileFactory' => $this->fileFactoryMock, + ] + ); + } + + /** + * @covers \Magento\Backup\Controller\Adminhtml\Index\Create::execute + * @return void + */ + public function testExecuteNotPost() + { + $redirectUrl = '*/*/index'; + $redirectUrlBackup = 'backup/index/index'; + + $this->requestMock->expects($this->any()) + ->method('isAjax') + ->willReturn(true); + $this->requestMock->expects($this->any()) + ->method('isPost') + ->willReturn(false); + $this->requestMock->expects($this->any()) + ->method('getParam') + ->with('maintenance_mode') + ->willReturn(true); + $this->dataBackendHelperMock->expects($this->any()) + ->method('getUrl') + ->with($redirectUrl, []) + ->willReturn($redirectUrlBackup); + $this->responseMock->expects($this->any()) + ->method('setRedirect') + ->with($redirectUrlBackup) + ->willReturnSelf(); + + $this->assertSame($this->responseMock, $this->createController->execute()); + } + + /** + * @covers \Magento\Backup\Controller\Adminhtml\Index\Create::execute + * @return void + */ + public function testExecutePermission() + { + $redirectUrl = '*/*/index'; + $redirectUrlBackup = 'backup/index/index'; + $backupType = 'db'; + $backupName = 'backup1'; + $response = '{"redirect_url":"backup\/index\/index"}'; + + $this->requestMock->expects($this->any()) + ->method('isAjax') + ->willReturn(true); + $this->requestMock->expects($this->any()) + ->method('isPost') + ->willReturn(true); + $this->requestMock->expects($this->any()) + ->method('getParam') + ->willReturnMap([ + ['type', null, $backupType], + ['backup_name', null, $backupName], + ]); + $this->dataBackendHelperMock->expects($this->any()) + ->method('getUrl') + ->with($redirectUrl, []) + ->willReturn($redirectUrlBackup); + $this->responseMock->expects($this->any()) + ->method('representJson') + ->with($response) + ->willReturnSelf(); + $this->maintenanceMode->expects($this->any()) + ->method('set') + ->with(true) + ->willReturn(false); + $this->backupFactoryMock->expects($this->any()) + ->method('create') + ->with($backupType) + ->willReturn($this->backupModelMock); + $this->backupModelMock->expects($this->any()) + ->method('setBackupExtension') + ->with($backupType) + ->willReturnSelf(); + $this->backupModelMock->expects($this->any()) + ->method('setBackupsDir') + ->willReturnSelf(); + $this->backupModelMock->expects($this->any()) + ->method('setTime') + ->willReturnSelf(); + $this->backupModelMock->expects($this->any()) + ->method('setName') + ->with($backupName) + ->willReturnSelf(); + $this->backupModelMock->expects($this->once()) + ->method('create') + ->willReturnSelf(); + $this->objectManagerMock->expects($this->any()) + ->method('get') + ->with(\Magento\Backup\Helper\Data::class) + ->willReturn($this->dataBackupHelperMock); + $this->dataBackupHelperMock->expects($this->any()) + ->method('getExtensionByType') + ->with($backupType) + ->willReturn($backupType); + $this->dataBackupHelperMock->expects($this->any()) + ->method('getBackupsDir') + ->willReturn('dir'); + + $this->assertNull($this->createController->execute()); + } +} diff --git a/app/code/Magento/Backup/composer.json b/app/code/Magento/Backup/composer.json index 51d6d3ad10808..626899580e441 100644 --- a/app/code/Magento/Backup/composer.json +++ b/app/code/Magento/Backup/composer.json @@ -9,7 +9,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.4", + "version": "100.1.6", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Braintree/Model/Adminhtml/System/Config/CountryCreditCard.php b/app/code/Magento/Braintree/Model/Adminhtml/System/Config/CountryCreditCard.php index 2474df84380e1..a9aa1a42d2489 100644 --- a/app/code/Magento/Braintree/Model/Adminhtml/System/Config/CountryCreditCard.php +++ b/app/code/Magento/Braintree/Model/Adminhtml/System/Config/CountryCreditCard.php @@ -56,6 +56,13 @@ public function __construct( public function beforeSave() { $value = $this->getValue(); + if (!is_array($value)) { + try { + $value = unserialize($value); + } catch (\InvalidArgumentException $e) { + $value = []; + } + } $result = []; foreach ($value as $data) { if (empty($data['country_id']) || empty($data['cc_types'])) { diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Report/BraintreeTransactionStub.php b/app/code/Magento/Braintree/Test/Unit/Model/Report/BraintreeTransactionStub.php index 5c28b94ac9811..372415d3530c0 100644 --- a/app/code/Magento/Braintree/Test/Unit/Model/Report/BraintreeTransactionStub.php +++ b/app/code/Magento/Braintree/Test/Unit/Model/Report/BraintreeTransactionStub.php @@ -34,10 +34,9 @@ public function __get($name) { if (array_key_exists($name, $this->_attributes)) { return $this->_attributes[$name]; - } else { - trigger_error('Undefined property on ' . get_class($this) . ': ' . $name, E_USER_NOTICE); - return null; } + trigger_error('Undefined property on ' . get_class($this) . ': ' . $name, E_USER_NOTICE); + return null; } /** diff --git a/app/code/Magento/Braintree/composer.json b/app/code/Magento/Braintree/composer.json index f74b5d22c776a..107a29730a8f4 100644 --- a/app/code/Magento/Braintree/composer.json +++ b/app/code/Magento/Braintree/composer.json @@ -24,7 +24,7 @@ "magento/module-checkout-agreements": "100.1.*" }, "type": "magento2-module", - "version": "100.1.8", + "version": "100.1.9", "license": [ "proprietary" ], diff --git a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php index e8efb593c441b..218814de99078 100644 --- a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php +++ b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php @@ -62,9 +62,8 @@ public function getChildren($item) if (isset($itemsArray[$item->getOrderItem()->getId()])) { return $itemsArray[$item->getOrderItem()->getId()]; - } else { - return null; } + return null; } /** @@ -186,9 +185,8 @@ public function getOrderItem() { if ($this->getItem() instanceof \Magento\Sales\Model\Order\Item) { return $this->getItem(); - } else { - return $this->getItem()->getOrderItem(); } + return $this->getItem()->getOrderItem(); } /** diff --git a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle/Option.php b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle/Option.php index d7f6f34b79b2f..b2ec246427afe 100644 --- a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle/Option.php +++ b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle/Option.php @@ -174,9 +174,8 @@ public function isSelected($selection) return in_array($selection->getSelectionId(), $selectedOptions); } elseif ($selectedOptions == 'None') { return false; - } else { - return $selection->getIsDefault() && $selection->isSaleable(); } + return $selection->getIsDefault() && $selection->isSaleable(); } /** diff --git a/app/code/Magento/Bundle/Block/Sales/Order/Items/Renderer.php b/app/code/Magento/Bundle/Block/Sales/Order/Items/Renderer.php index 144115bee48d7..7932e41ef8d7e 100644 --- a/app/code/Magento/Bundle/Block/Sales/Order/Items/Renderer.php +++ b/app/code/Magento/Bundle/Block/Sales/Order/Items/Renderer.php @@ -114,9 +114,8 @@ public function getValueHtml($item) if ($attributes = $this->getSelectionAttributes($item)) { return sprintf('%d', $attributes['qty']) . ' x ' . $this->escapeHtml($item->getName()) . " " . $this->getOrder()->formatPrice($attributes['price']); - } else { - return $this->escapeHtml($item->getName()); } + return $this->escapeHtml($item->getName()); } /** @@ -151,9 +150,8 @@ public function getChildren($item) if (isset($itemsArray[$item->getOrderItem()->getId()])) { return $itemsArray[$item->getOrderItem()->getId()]; - } else { - return null; } + return null; } /** diff --git a/app/code/Magento/Bundle/Model/Plugin/PriceBackend.php b/app/code/Magento/Bundle/Model/Plugin/PriceBackend.php index f3c0548f76e5d..1914d5b5146c3 100644 --- a/app/code/Magento/Bundle/Model/Plugin/PriceBackend.php +++ b/app/code/Magento/Bundle/Model/Plugin/PriceBackend.php @@ -29,8 +29,7 @@ public function aroundValidate( && $object->getPriceType() == \Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC ) { return true; - } else { - return $proceed($object); } + return $proceed($object); } } diff --git a/app/code/Magento/Bundle/Model/Product/Type.php b/app/code/Magento/Bundle/Model/Product/Type.php index 58a0418ec3ebd..affabcb7be4f3 100644 --- a/app/code/Magento/Bundle/Model/Product/Type.php +++ b/app/code/Magento/Bundle/Model/Product/Type.php @@ -948,9 +948,8 @@ public function shakeSelections($firstItem, $secondItem) ]; if ($aPosition == $bPosition) { return 0; - } else { - return $aPosition < $bPosition ? -1 : 1; } + return $aPosition < $bPosition ? -1 : 1; } /** diff --git a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/AbstractItems.php b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/AbstractItems.php index dd126b874745d..6741f62fad884 100644 --- a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/AbstractItems.php +++ b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/AbstractItems.php @@ -44,9 +44,8 @@ public function getChildren($item) if (isset($itemsArray[$item->getOrderItem()->getId()])) { return $itemsArray[$item->getOrderItem()->getId()]; - } else { - return null; } + return null; } /** @@ -196,9 +195,8 @@ public function getOrderItem() { if ($this->getItem() instanceof \Magento\Sales\Model\Order\Item) { return $this->getItem(); - } else { - return $this->getItem()->getOrderItem(); } + return $this->getItem()->getOrderItem(); } /** diff --git a/app/code/Magento/Bundle/Pricing/Adjustment/Calculator.php b/app/code/Magento/Bundle/Pricing/Adjustment/Calculator.php index 52d7f3a652f82..6d8b2105e9cf0 100644 --- a/app/code/Magento/Bundle/Pricing/Adjustment/Calculator.php +++ b/app/code/Magento/Bundle/Pricing/Adjustment/Calculator.php @@ -267,9 +267,8 @@ public function calculateBundleAmount($basePriceValue, $bundleProduct, $selectio { if ($bundleProduct->getPriceType() == Price::PRICE_TYPE_FIXED) { return $this->calculateFixedBundleAmount($basePriceValue, $bundleProduct, $selectionPriceList, $exclude); - } else { - return $this->calculateDynamicBundleAmount($basePriceValue, $bundleProduct, $selectionPriceList, $exclude); } + return $this->calculateDynamicBundleAmount($basePriceValue, $bundleProduct, $selectionPriceList, $exclude); } /** diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php index cdfe31358cc15..60245bef722c6 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php @@ -163,8 +163,7 @@ public function getProduct() { if ($this->bundleProduct->getPriceType() == Price::PRICE_TYPE_DYNAMIC) { return parent::getProduct(); - } else { - return $this->bundleProduct; } + return $this->bundleProduct; } } diff --git a/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php b/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php index df63c9c03cbf6..4f2f35b076d82 100644 --- a/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php @@ -124,9 +124,8 @@ public function getValue() $this->priceInfo ->getPrice(BundleDiscountPrice::PRICE_CODE) ->calculateDiscount($configuredOptionsAmount); - } else { - return parent::getValue(); } + return parent::getValue(); } /** diff --git a/app/code/Magento/Bundle/composer.json b/app/code/Magento/Bundle/composer.json index 474275f00c069..66111e373a162 100644 --- a/app/code/Magento/Bundle/composer.json +++ b/app/code/Magento/Bundle/composer.json @@ -25,7 +25,7 @@ "magento/module-bundle-sample-data": "Sample Data version:100.1.*" }, "type": "magento2-module", - "version": "100.1.6", + "version": "100.1.7", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/BundleImportExport/composer.json b/app/code/Magento/BundleImportExport/composer.json index 7ef6c6cd48f6b..3c6c318fccee6 100644 --- a/app/code/Magento/BundleImportExport/composer.json +++ b/app/code/Magento/BundleImportExport/composer.json @@ -11,7 +11,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.4", + "version": "100.1.5", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/CacheInvalidate/composer.json b/app/code/Magento/CacheInvalidate/composer.json index 01bbd0d8d97bd..c5051eed283ef 100644 --- a/app/code/Magento/CacheInvalidate/composer.json +++ b/app/code/Magento/CacheInvalidate/composer.json @@ -7,7 +7,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Captcha/composer.json b/app/code/Magento/Captcha/composer.json index 63f6b9c84279b..8216b31defa51 100644 --- a/app/code/Magento/Captcha/composer.json +++ b/app/code/Magento/Captcha/composer.json @@ -10,7 +10,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Set/Main.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Set/Main.php index f33184fd92b7d..460184fa944e9 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Set/Main.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Set/Main.php @@ -5,13 +5,14 @@ */ namespace Magento\Catalog\Block\Adminhtml\Product\Attribute\Set; +use Magento\Catalog\Model\Entity\Product\Attribute\Group\AttributeMapperInterface; + /** * Adminhtml Catalog Attribute Set Main Block * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @author Magento Core Team */ -use Magento\Catalog\Model\Entity\Product\Attribute\Group\AttributeMapperInterface; - class Main extends \Magento\Backend\Block\Template { /** @@ -89,25 +90,25 @@ protected function _prepareLayout() { $setId = $this->_getSetId(); - $this->addChild('group_tree', 'Magento\Catalog\Block\Adminhtml\Product\Attribute\Set\Main\Tree\Group'); + $this->addChild('group_tree', \Magento\Catalog\Block\Adminhtml\Product\Attribute\Set\Main\Tree\Group::class); - $this->addChild('edit_set_form', 'Magento\Catalog\Block\Adminhtml\Product\Attribute\Set\Main\Formset'); + $this->addChild('edit_set_form', \Magento\Catalog\Block\Adminhtml\Product\Attribute\Set\Main\Formset::class); $this->addChild( 'delete_group_button', - 'Magento\Backend\Block\Widget\Button', + \Magento\Backend\Block\Widget\Button::class, ['label' => __('Delete Selected Group'), 'onclick' => 'editSet.submit();', 'class' => 'delete'] ); $this->addChild( 'add_group_button', - 'Magento\Backend\Block\Widget\Button', + \Magento\Backend\Block\Widget\Button::class, ['label' => __('Add New'), 'onclick' => 'editSet.addGroup();', 'class' => 'add'] ); $this->getToolbar()->addChild( 'back_button', - 'Magento\Backend\Block\Widget\Button', + \Magento\Backend\Block\Widget\Button::class, [ 'label' => __('Back'), 'onclick' => 'setLocation(\'' . $this->getUrl('catalog/*/') . '\')', @@ -117,14 +118,14 @@ protected function _prepareLayout() $this->getToolbar()->addChild( 'reset_button', - 'Magento\Backend\Block\Widget\Button', + \Magento\Backend\Block\Widget\Button::class, ['label' => __('Reset'), 'onclick' => 'window.location.reload()', 'class' => 'reset'] ); if (!$this->getIsCurrentSetDefault()) { $this->getToolbar()->addChild( 'delete_button', - 'Magento\Backend\Block\Widget\Button', + \Magento\Backend\Block\Widget\Button::class, [ 'label' => __('Delete'), 'onclick' => 'deleteConfirm(\'' . $this->escapeJsQuote( @@ -143,7 +144,7 @@ protected function _prepareLayout() $this->getToolbar()->addChild( 'save_button', - 'Magento\Backend\Block\Widget\Button', + \Magento\Backend\Block\Widget\Button::class, [ 'label' => __('Save'), 'onclick' => 'editSet.save();', @@ -153,7 +154,7 @@ protected function _prepareLayout() $this->addChild( 'rename_button', - 'Magento\Backend\Block\Widget\Button', + \Magento\Backend\Block\Widget\Button::class, ['label' => __('New Set Name'), 'onclick' => 'editSet.rename()'] ); @@ -228,7 +229,7 @@ public function getGroupTreeJson() /* @var $node \Magento\Eav\Model\Entity\Attribute\Group */ foreach ($groups as $node) { $item = []; - $item['text'] = $node->getAttributeGroupName(); + $item['text'] = $this->escapeHtml($node->getAttributeGroupName()); $item['id'] = $node->getAttributeGroupId(); $item['cls'] = 'folder'; $item['allowDrop'] = true; @@ -275,7 +276,7 @@ public function getAttributeTreeJson() foreach ($attributes as $child) { $attr = [ - 'text' => $child->getAttributeCode(), + 'text' => $this->escapeHtml($child->getAttributeCode()), 'id' => $child->getAttributeId(), 'cls' => 'leaf', 'allowDrop' => false, diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index c828074e24674..386fcf8eff9b2 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -340,7 +340,7 @@ public function getIdentities() * Get post parameters * * @param \Magento\Catalog\Model\Product $product - * @return string + * @return array */ public function getAddToCartPostParams(\Magento\Catalog\Model\Product $product) { diff --git a/app/code/Magento/Catalog/Block/Product/View.php b/app/code/Magento/Catalog/Block/Product/View.php index 987477c83c9e5..082ea504f0f69 100644 --- a/app/code/Magento/Catalog/Block/Product/View.php +++ b/app/code/Magento/Catalog/Block/Product/View.php @@ -145,7 +145,7 @@ protected function _prepareLayout() if ($description) { $this->pageConfig->setDescription($description); } else { - $this->pageConfig->setDescription($this->string->substr($product->getDescription(), 0, 255)); + $this->pageConfig->setDescription($this->string->substr(strip_tags($product->getDescription()), 0, 255)); } if ($this->_productHelper->canUseCanonicalTag()) { $this->pageConfig->addRemotePageAsset( diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php index 8555503bfa79d..384022f558dce 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php @@ -123,8 +123,7 @@ public function execute() return $resultRedirect->setPath('catalog/*/', ['_current' => true, 'id' => null]); } - $data['general'] = $this->getRequest()->getPostValue(); - $categoryPostData = $data['general']; + $categoryPostData = $this->getRequest()->getPostValue(); $isNewCategory = !isset($categoryPostData['entity_id']); $categoryPostData = $this->stringToBoolConverting($categoryPostData); diff --git a/app/code/Magento/Catalog/Model/Category.php b/app/code/Magento/Catalog/Model/Category.php index 5b812052d730d..46ea76b4090b9 100644 --- a/app/code/Magento/Catalog/Model/Category.php +++ b/app/code/Magento/Catalog/Model/Category.php @@ -114,6 +114,11 @@ class Category extends \Magento\Catalog\Model\AbstractModel implements */ protected $_url; + /** + * @var ResourceModel\Category + */ + protected $_resource; + /** * URL rewrite model * @@ -327,6 +332,16 @@ protected function getCustomAttributesCodes() return $this->customAttributesCodes; } + /** + * @throws \Magento\Framework\Exception\LocalizedException + * @return \Magento\Catalog\Model\ResourceModel\Category + * @deprecated because resource models should be used directly + */ + protected function _getResource() + { + return parent::_getResource(); + } + /** * Get flat resource model flag * @@ -1132,19 +1147,21 @@ public function getIdentities() { $identities = []; if ($this->getId()) { - $identities[] = self::CACHE_TAG . '_' . $this->getId(); - } - if ($this->getId() - && ( - $this->hasDataChanges() - || $this->isDeleted() - || $this->dataHasChangedFor(self::KEY_INCLUDE_IN_MENU) - ) - ) { - $identities[] = Product::CACHE_PRODUCT_CATEGORY_TAG . '_' . $this->getId(); - } - if ($this->getId() && $this->isObjectNew()) { - $identities[] = self::CACHE_TAG; + if ($this->getAffectedCategoryIds()) { + foreach (array_unique($this->getAffectedCategoryIds()) as $affectedCategoryId) { + $identities[] = self::CACHE_TAG . '_' . $affectedCategoryId; + } + } else { + $identities[] = self::CACHE_TAG . '_' . $this->getId(); + } + + if ($this->hasDataChanges() || $this->isDeleted() || $this->dataHasChangedFor(self::KEY_INCLUDE_IN_MENU)) { + $identities[] = Product::CACHE_PRODUCT_CATEGORY_TAG . '_' . $this->getId(); + } + + if ($this->isObjectNew()) { + $identities[] = self::CACHE_TAG; + } } return $identities; diff --git a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php index 3950fd1eee719..818a761814548 100644 --- a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php +++ b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php @@ -52,11 +52,6 @@ class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend */ private $imageUploader; - /** - * @var string - */ - private $additionalData = '_additional_data_'; - /** * Image constructor. * @@ -85,9 +80,9 @@ public function beforeSave($object) { $attributeName = $this->getAttribute()->getName(); $value = $object->getData($attributeName); + $imageName = $this->getUploadedImageName($value); - if ($imageName = $this->getUploadedImageName($value)) { - $object->setData($this->additionalData . $attributeName, $value); + if ($imageName) { $object->setData($attributeName, $imageName); } else if (!is_string($value)) { $object->setData($attributeName, ''); @@ -130,27 +125,15 @@ private function getImageUploader() } /** - * Check if temporary file is available for new image upload. - * - * @param array $value - * @return bool - */ - private function isTmpFileAvailable($value) - { - return is_array($value) && isset($value[0]['tmp_name']); - } - - /** - * Save uploaded file and set its name to category + * Save uploaded file and set its name to category. * * @param \Magento\Framework\DataObject $object * @return \Magento\Catalog\Model\Category\Attribute\Backend\Image */ public function afterSave($object) { - $value = $object->getData($this->additionalData . $this->getAttribute()->getName()); - - if ($this->isTmpFileAvailable($value) && $imageName = $this->getUploadedImageName($value)) { + $imageName = $object->getData($this->getAttribute()->getName(), null); + if ($imageName) { try { $this->getImageUploader()->moveFileFromTmp($imageName); } catch (\Exception $e) { diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php index 268bed36af1ad..1e7fefddf5e87 100644 --- a/app/code/Magento/Catalog/Model/Product.php +++ b/app/code/Magento/Catalog/Model/Product.php @@ -117,6 +117,11 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements */ protected $_urlModel = null; + /** + * @var ResourceModel\Product + */ + protected $_resource; + /** * @var string */ @@ -469,6 +474,18 @@ protected function _construct() $this->_init('Magento\Catalog\Model\ResourceModel\Product'); } + /** + * Get resource instance + * + * @throws \Magento\Framework\Exception\LocalizedException + * @return \Magento\Catalog\Model\ResourceModel\Product + * @deprecated because resource models should be used directly + */ + protected function _getResource() + { + return parent::_getResource(); + } + /** * {@inheritdoc} */ diff --git a/app/code/Magento/Catalog/Model/Product/Option.php b/app/code/Magento/Catalog/Model/Product/Option.php index f7a296a821241..51b32b3db9834 100644 --- a/app/code/Magento/Catalog/Model/Product/Option.php +++ b/app/code/Magento/Catalog/Model/Product/Option.php @@ -391,6 +391,11 @@ public function beforeSave() } } } + + if ($this->getGroupByType($this->getData('type')) === self::OPTION_GROUP_FILE) { + $this->cleanFileExtensions(); + } + return $this; } @@ -912,5 +917,22 @@ private function getMetadataPool() } return $this->metadataPool; } + + /** + * Clears all non-accepted characters from file_extension field. + * + * @return void + */ + private function cleanFileExtensions() + { + $rawExtensions = $this->getFileExtension(); + $matches = []; + preg_match_all('/(?[a-z0-9]+)/i', strtolower($rawExtensions), $matches); + if (!empty($matches)) { + $extensions = implode(', ', array_unique($matches['extensions'])); + } + $this->setFileExtension($extensions); + } + //@codeCoverageIgnoreEnd } diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php index 325d8ceee0d39..38831ed9138f1 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php @@ -311,7 +311,7 @@ public function joinUrlRewrite() ['request_path'], sprintf( '{{table}}.is_autogenerated = 1 AND {{table}}.store_id = %d AND {{table}}.entity_type = \'%s\'', - $this->_storeManager->getStore()->getId(), + $this->getStoreId(), CategoryUrlRewriteGenerator::ENTITY_TYPE ), 'left' diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Collection/AbstractCollection.php b/app/code/Magento/Catalog/Model/ResourceModel/Collection/AbstractCollection.php index d329ca6f51572..188167b7c609f 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Collection/AbstractCollection.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Collection/AbstractCollection.php @@ -137,7 +137,7 @@ public function getDefaultStoreId() * * @param string $table * @param array|int $attributeIds - * @return \Magento\Eav\Model\Entity\Collection\AbstractCollection + * @return \Magento\Framework\DB\Select */ protected function _getLoadAttributesSelect($table, $attributeIds = []) { diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php index 406bd595401ca..886466c3ffd09 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php @@ -1535,7 +1535,7 @@ protected function getEntityPkName(\Magento\Eav\Model\Entity\AbstractEntity $ent } /** - * Add requere tax percent flag for product collection + * Add require tax percent flag for product collection * * @return $this */ diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php index 88ab0f5a1ce63..247a124a7af1d 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php @@ -164,8 +164,7 @@ public function testAfterSave() $object = new \Magento\Framework\DataObject( [ - 'test_attribute' => 'test1234.jpg', - '_additional_data_test_attribute' => [['name' => 'test1234.jpg', 'tmp_name' => 'test-test-1234']] + 'test_attribute' => 'test1234.jpg' ] ); $model->afterSave($object); @@ -208,7 +207,7 @@ public function testAfterSaveWithExceptions() ->with($this->equalTo($exception)); $object = new \Magento\Framework\DataObject( [ - '_additional_data_test_attribute' => [['name' => 'test1234.jpg', 'tmp_name' => 'test-test-1234']] + 'test_attribute' => 'test1234.jpg' ] ); $model->afterSave($object); diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php index 41dd17ac203b4..c8ee0fc13758d 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php @@ -655,4 +655,22 @@ public function testGetIdentities() $category->setId(42); $this->assertNotEmpty($category->getIdentities()); } + + /** + * @return void + */ + public function testGetIdentitiesWithAffectedCategories() + { + $category = $this->getCategoryModel(); + $expectedIdentities = [ + 'catalog_category_1', + 'catalog_category_2', + 'catalog_category_3', + 'catalog_category_product_1', + ]; + $category->setId(1); + $category->setAffectedCategoryIds([1,2,3]); + + $this->assertEquals($expectedIdentities, $category->getIdentities()); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/OptionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/OptionTest.php index 36aac944953cf..a61cc2889fbf9 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/OptionTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/OptionTest.php @@ -8,6 +8,9 @@ use \Magento\Catalog\Model\Product\Option; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +/** + * Tests \Magento\Catalog\Model\Product\Option. + */ class OptionTest extends \PHPUnit_Framework_TestCase { /** @@ -22,9 +25,9 @@ class OptionTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->productMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); + $this->productMock = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false); $objectManager = new ObjectManager($this); - $this->model = $objectManager->getObject('Magento\Catalog\Model\Product\Option'); + $this->model = $objectManager->getObject(\Magento\Catalog\Model\Product\Option::class); $this->model->setProduct($this->productMock); } @@ -38,7 +41,7 @@ public function testGetProductSku() public function testGetRegularPrice() { $priceInfoMock = $this->getMockForAbstractClass( - 'Magento\Framework\Pricing\PriceInfoInterface', + \Magento\Framework\Pricing\PriceInfoInterface::class, [], '', false, @@ -47,7 +50,7 @@ public function testGetRegularPrice() ['getAmount', 'getPrice'] ); $priceInfoMock->expects($this->once())->method('getPrice')->willReturnSelf(); - $amountMock = $this->getMockForAbstractClass('Magento\Framework\Pricing\Amount\AmountInterface'); + $amountMock = $this->getMockForAbstractClass(\Magento\Framework\Pricing\Amount\AmountInterface::class); $priceInfoMock->expects($this->once())->method('getAmount')->willReturn($amountMock); $this->productMock->expects($this->once())->method('getPriceInfo')->willReturn($priceInfoMock); @@ -59,4 +62,41 @@ public function testGetRegularPrice() $this->model->setPriceType(null); $this->assertEquals(50, $this->model->getRegularPrice()); } + + /** + * Tests removing ineligible characters from file_extension. + * + * @param string $rawExtensions + * @param string $expectedExtensions + * @dataProvider beforeSaveFileOptionDataProvider + */ + public function testBeforeSaveFileOption($rawExtensions, $expectedExtensions) + { + $this->model->setType(Option::OPTION_GROUP_FILE); + $this->model->setFileExtension($rawExtensions); + $this->model->beforeSave(); + $actualExtensions = $this->model->getFileExtension(); + $this->assertEquals( + $expectedExtensions, + $actualExtensions + ); + } + + /** + * Data provider for testBeforeSaveFileOption. + * + * @return array + */ + public function beforeSaveFileOptionDataProvider() + { + return [ + ['JPG, PNG, GIF', 'jpg, png, gif'], + ['jpg, jpg, jpg', 'jpg'], + ['jpg, png, gif', 'jpg, png, gif'], + ['jpg png gif', 'jpg, png, gif'], + ['!jpg@png#gif%', 'jpg, png, gif'], + ['jpg, png, 123', 'jpg, png, 123'], + ['', ''], + ]; + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Category/Collection/UrlRewriteTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Category/Collection/UrlRewriteTest.php new file mode 100644 index 0000000000000..d3b3ce05ee4b8 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Category/Collection/UrlRewriteTest.php @@ -0,0 +1,39 @@ +_model = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Category\Collection::class) + ->disableOriginalConstructor() + ->setMethods(['joinTable']) + ->getMock(); + } + + public function testStoreIdUsedByUrlRewrite() + { + $cond = '{{table}}.is_autogenerated = 1 AND {{table}}.store_id = 100 AND {{table}}.entity_type = \'category\''; + $this->_model->expects($this->once()) + ->method('joinTable') + ->with( + $this->anything(), + $this->anything(), + $this->anything(), + $this->equalTo($cond), + $this->anything() + ); + $this->_model->setStoreId(100); + $this->_model->joinUrlRewrite(); + } +} diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php index 0b2972d83cde7..9f87d831a4ea6 100755 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php @@ -991,6 +991,7 @@ protected function getFileExtensionFieldConfig($sortOrder) 'data' => [ 'config' => [ 'label' => __('Compatible File Extensions'), + 'notice' => __('Enter separated extensions, like: png, jpg, gif.'), 'componentType' => Field::NAME, 'formElement' => Input::NAME, 'dataScope' => static::FIELD_FILE_EXTENSION_NAME, diff --git a/app/code/Magento/Catalog/composer.json b/app/code/Magento/Catalog/composer.json index 4a8d90ea7a5ff..5f0f089030160 100644 --- a/app/code/Magento/Catalog/composer.json +++ b/app/code/Magento/Catalog/composer.json @@ -33,7 +33,7 @@ "magento/module-catalog-sample-data": "Sample Data version:100.1.*" }, "type": "magento2-module", - "version": "101.0.11", + "version": "101.0.13", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml index 0f17b026774b7..ce1e023712f0f 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml @@ -266,7 +266,7 @@ } var newNode = new Ext.tree.TreeNode({ - text : group_name, + text : group_name.escapeHTML(), cls : 'folder', allowDrop : true, allowDrag : true @@ -295,9 +295,10 @@ validateGroupName : function(name, exceptNodeId) { var textNode; - var result = true; + result = true; name = name.strip(); + name = name.escapeHTML(); if (name === '') { result = false; } diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/file.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/file.phtml index 86fdd8705931d..6f6ff90d38030 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/file.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/file.phtml @@ -41,6 +41,7 @@ +
x %2 px.', '', diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/category_form.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/category_form.xml index cd0b2ca1f03ce..1789d83970948 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/category_form.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/category_form.xml @@ -183,6 +183,7 @@ false false false + true ui/form/field category diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js index b8109129436df..06b670df8a38b 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js @@ -141,6 +141,7 @@ define([ // strip tags tmpElement = document.createElement('div'); + str = str.replace(/(<([^>]+)>)/ig, ''); tmpElement.innerHTML = str; str = tmpElement.textContent || tmpElement.innerText || ''; diff --git a/app/code/Magento/Catalog/view/base/templates/product/price/amount/default.phtml b/app/code/Magento/Catalog/view/base/templates/product/price/amount/default.phtml index ef6b1cd15c7c9..18c951f51df09 100644 --- a/app/code/Magento/Catalog/view/base/templates/product/price/amount/default.phtml +++ b/app/code/Magento/Catalog/view/base/templates/product/price/amount/default.phtml @@ -19,18 +19,15 @@ getPriceDisplayLabel()) ? 'data-label="' . $block->getPriceDisplayLabel() . $block->getPriceDisplayInclExclTaxes() . '"' : '' ?> data-price-amount="getDisplayValue(); ?>" data-price-type="getPriceType(); ?>" - class="price-wrapper getPriceWrapperCss(); ?>"> - formatCurrency($block->getDisplayValue(), (bool)$block->getIncludeContainer()) ?> + class="price-wrapper getPriceWrapperCss(); ?>" + getSchema() ? ' itemprop="price"' : '' ?>> + formatCurrency($block->getDisplayValue(), (bool)$block->getIncludeContainer()) ?> - getSchema()): ?> - - getDisplayValue() ?> - - hasAdjustmentsHtml()): ?> getAdjustmentsHtml() ?> getSchema()): ?> + diff --git a/app/code/Magento/Catalog/view/base/web/js/price-options.js b/app/code/Magento/Catalog/view/base/web/js/price-options.js index cbd8ab95618c1..d66c9593c806c 100644 --- a/app/code/Magento/Catalog/view/base/web/js/price-options.js +++ b/app/code/Magento/Catalog/view/base/web/js/price-options.js @@ -19,8 +19,10 @@ define([ optionConfig: {}, optionHandlers: {}, optionTemplate: '<%= data.label %>' + - '<% if (data.finalPrice.value) { %>' + + '<% if (data.finalPrice.value > 0) { %>' + ' +<%- data.finalPrice.formatted %>' + + '<% } else if (data.finalPrice.value < 0) { %>' + + ' <%- data.finalPrice.formatted %>' + '<% } %>', controlContainer: 'dd' }; diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml index a8f9487058eda..6037704570dae 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml @@ -40,22 +40,10 @@
-isRedirectToCartEnabled()) : ?> - - - - diff --git a/app/code/Magento/CatalogImportExport/composer.json b/app/code/Magento/CatalogImportExport/composer.json index 59412887bfaaf..920bf0941cd47 100644 --- a/app/code/Magento/CatalogImportExport/composer.json +++ b/app/code/Magento/CatalogImportExport/composer.json @@ -16,7 +16,7 @@ "ext-ctype": "*" }, "type": "magento2-module", - "version": "100.1.8", + "version": "100.1.9", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/CatalogInventory/composer.json b/app/code/Magento/CatalogInventory/composer.json index 536d9a0b7ebc0..61ace08b645ec 100644 --- a/app/code/Magento/CatalogInventory/composer.json +++ b/app/code/Magento/CatalogInventory/composer.json @@ -13,7 +13,7 @@ "magento/module-ui": "100.1.*" }, "type": "magento2-module", - "version": "100.1.7", + "version": "100.1.8", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/CatalogInventory/i18n/en_US.csv b/app/code/Magento/CatalogInventory/i18n/en_US.csv index 6dbbf9a2d2b7a..14379ec76f542 100644 --- a/app/code/Magento/CatalogInventory/i18n/en_US.csv +++ b/app/code/Magento/CatalogInventory/i18n/en_US.csv @@ -48,11 +48,7 @@ Inventory,Inventory "Only X left Threshold","Only X left Threshold" "Display Products Availability in Stock on Storefront","Display Products Availability in Stock on Storefront" "Product Stock Options","Product Stock Options" -" - Please note that these settings apply to individual items in the cart, not to the entire cart. - "," - Please note that these settings apply to individual items in the cart, not to the entire cart. - " +"Please note that these settings apply to individual items in the cart, not to the entire cart.","Please note that these settings apply to individual items in the cart, not to the entire cart." "Manage Stock","Manage Stock" Backorders,Backorders "Maximum Qty Allowed in Shopping Cart","Maximum Qty Allowed in Shopping Cart" diff --git a/app/code/Magento/CatalogRule/composer.json b/app/code/Magento/CatalogRule/composer.json index b9d25a29e7f65..8c33932e08cdb 100644 --- a/app/code/Magento/CatalogRule/composer.json +++ b/app/code/Magento/CatalogRule/composer.json @@ -17,7 +17,7 @@ "magento/module-catalog-rule-sample-data": "Sample Data version:100.1.*" }, "type": "magento2-module", - "version": "100.1.5", + "version": "100.1.6", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_edit.xml b/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_edit.xml index 505557b8950b2..1a3227a4d79b2 100644 --- a/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_edit.xml +++ b/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_edit.xml @@ -5,7 +5,7 @@ * See COPYING.txt for license details. */ --> - + diff --git a/app/code/Magento/CatalogRuleConfigurable/composer.json b/app/code/Magento/CatalogRuleConfigurable/composer.json index 2f01e9617e449..db6548145966d 100644 --- a/app/code/Magento/CatalogRuleConfigurable/composer.json +++ b/app/code/Magento/CatalogRuleConfigurable/composer.json @@ -14,7 +14,7 @@ "magento/module-catalog-rule": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/CatalogSearch/Block/Advanced/Form.php b/app/code/Magento/CatalogSearch/Block/Advanced/Form.php index baa4f75d185a6..d205c5d937a3d 100644 --- a/app/code/Magento/CatalogSearch/Block/Advanced/Form.php +++ b/app/code/Magento/CatalogSearch/Block/Advanced/Form.php @@ -197,16 +197,16 @@ public function getCurrency($attribute) public function getAttributeInputType($attribute) { $dataType = $attribute->getBackend()->getType(); - $imputType = $attribute->getFrontend()->getInputType(); - if ($imputType == 'select' || $imputType == 'multiselect') { + $inputType = $attribute->getFrontend()->getInputType(); + if ($inputType == 'select' || $inputType == 'multiselect') { return 'select'; } - if ($imputType == 'boolean') { + if ($inputType == 'boolean') { return 'yesno'; } - if ($imputType == 'price') { + if ($inputType == 'price') { return 'price'; } diff --git a/app/code/Magento/CatalogSearch/composer.json b/app/code/Magento/CatalogSearch/composer.json index 0990dc8b01349..281db72dfcd16 100644 --- a/app/code/Magento/CatalogSearch/composer.json +++ b/app/code/Magento/CatalogSearch/composer.json @@ -15,7 +15,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.8", + "version": "100.1.9", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/CatalogUrlRewrite/composer.json b/app/code/Magento/CatalogUrlRewrite/composer.json index 5bbccfc4b77ae..c0abedfa012cc 100644 --- a/app/code/Magento/CatalogUrlRewrite/composer.json +++ b/app/code/Magento/CatalogUrlRewrite/composer.json @@ -14,7 +14,7 @@ "magento/module-ui": "100.1.*" }, "type": "magento2-module", - "version": "100.1.5", + "version": "100.1.6", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/CatalogWidget/composer.json b/app/code/Magento/CatalogWidget/composer.json index 734be1c11523e..29c38a350fe3b 100644 --- a/app/code/Magento/CatalogWidget/composer.json +++ b/app/code/Magento/CatalogWidget/composer.json @@ -14,7 +14,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.4", + "version": "100.1.5", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Checkout/Block/Cart/Shipping.php b/app/code/Magento/Checkout/Block/Cart/Shipping.php index b3a9e8d02201f..7e193237a9715 100644 --- a/app/code/Magento/Checkout/Block/Cart/Shipping.php +++ b/app/code/Magento/Checkout/Block/Cart/Shipping.php @@ -64,7 +64,7 @@ public function getJsLayout() foreach ($this->layoutProcessors as $processor) { $this->jsLayout = $processor->process($this->jsLayout); } - return \Zend_Json::encode($this->jsLayout); + return json_encode($this->jsLayout, JSON_HEX_TAG); } /** diff --git a/app/code/Magento/Checkout/Block/Cart/Totals.php b/app/code/Magento/Checkout/Block/Cart/Totals.php index 7861080d5d4b5..3392367008e2d 100644 --- a/app/code/Magento/Checkout/Block/Cart/Totals.php +++ b/app/code/Magento/Checkout/Block/Cart/Totals.php @@ -66,7 +66,7 @@ public function getJsLayout() foreach ($this->layoutProcessors as $processor) { $this->jsLayout = $processor->process($this->jsLayout); } - return parent::getJsLayout(); + return json_encode($this->jsLayout, JSON_HEX_TAG); } /** diff --git a/app/code/Magento/Checkout/Block/Onepage.php b/app/code/Magento/Checkout/Block/Onepage.php index ebb5797f2ac03..b232425f95b40 100644 --- a/app/code/Magento/Checkout/Block/Onepage.php +++ b/app/code/Magento/Checkout/Block/Onepage.php @@ -66,7 +66,7 @@ public function getJsLayout() foreach ($this->layoutProcessors as $processor) { $this->jsLayout = $processor->process($this->jsLayout); } - return \Zend_Json::encode($this->jsLayout); + return json_encode($this->jsLayout, JSON_HEX_TAG); } /** diff --git a/app/code/Magento/Checkout/CustomerData/DefaultItem.php b/app/code/Magento/Checkout/CustomerData/DefaultItem.php index 6e917366c9cd2..9351685405a60 100644 --- a/app/code/Magento/Checkout/CustomerData/DefaultItem.php +++ b/app/code/Magento/Checkout/CustomerData/DefaultItem.php @@ -6,6 +6,8 @@ namespace Magento\Checkout\CustomerData; +use Magento\Framework\App\ObjectManager; + /** * Default item */ @@ -36,12 +38,20 @@ class DefaultItem extends AbstractItem */ protected $checkoutHelper; + /** + * Escaper + * + * @var \Magento\Framework\Escaper + */ + private $escaper; + /** * @param \Magento\Catalog\Helper\Image $imageHelper * @param \Magento\Msrp\Helper\Data $msrpHelper * @param \Magento\Framework\UrlInterface $urlBuilder * @param \Magento\Catalog\Helper\Product\ConfigurationPool $configurationPool * @param \Magento\Checkout\Helper\Data $checkoutHelper + * @param \Magento\Framework\Escaper|null $escaper * @codeCoverageIgnore */ public function __construct( @@ -49,13 +59,15 @@ public function __construct( \Magento\Msrp\Helper\Data $msrpHelper, \Magento\Framework\UrlInterface $urlBuilder, \Magento\Catalog\Helper\Product\ConfigurationPool $configurationPool, - \Magento\Checkout\Helper\Data $checkoutHelper + \Magento\Checkout\Helper\Data $checkoutHelper, + \Magento\Framework\Escaper $escaper = null ) { $this->configurationPool = $configurationPool; $this->imageHelper = $imageHelper; $this->msrpHelper = $msrpHelper; $this->urlBuilder = $urlBuilder; $this->checkoutHelper = $checkoutHelper; + $this->escaper = $escaper ?: ObjectManager::getInstance()->get(\Magento\Framework\Escaper::class); } /** @@ -64,6 +76,8 @@ public function __construct( protected function doGetItemData() { $imageHelper = $this->imageHelper->init($this->getProductForThumbnail(), 'mini_cart_product_thumbnail'); + $productName = $this->escaper->escapeHtml($this->item->getProduct()->getName()); + return [ 'options' => $this->getOptionList(), 'qty' => $this->item->getQty() * 1, @@ -71,7 +85,7 @@ protected function doGetItemData() 'configure_url' => $this->getConfigureUrl(), 'is_visible_in_site_visibility' => $this->item->getProduct()->isVisibleInSiteVisibility(), 'product_id' => $this->item->getProduct()->getId(), - 'product_name' => $this->item->getProduct()->getName(), + 'product_name' => $productName, 'product_sku' => $this->item->getProduct()->getSku(), 'product_url' => $this->getProductUrl(), 'product_has_url' => $this->hasProductUrl(), diff --git a/app/code/Magento/Checkout/composer.json b/app/code/Magento/Checkout/composer.json index 3b309c2dc8eef..041e9c4aa50bd 100644 --- a/app/code/Magento/Checkout/composer.json +++ b/app/code/Magento/Checkout/composer.json @@ -26,7 +26,7 @@ "magento/module-cookie": "100.1.*" }, "type": "magento2-module", - "version": "100.1.10", + "version": "100.1.12", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml b/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml index a402f0f9d99b7..ddbc32d9012e4 100644 --- a/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml +++ b/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml @@ -19,7 +19,7 @@
+ class="input-text qty" data-validate="escapeHtml(json_encode($block->getQuantityValidators())) ?>"/>
diff --git a/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml b/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml index f51acf56cfd33..9e44f8f4b48aa 100644 --- a/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml +++ b/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml @@ -90,7 +90,7 @@ $canApplyMsrp = $helper->isShowBeforeOrderConfirm($product) && $helper->isMinima
getIsNeedToDisplaySideBar()): ?> -
- + diff --git a/app/code/Magento/CheckoutAgreements/composer.json b/app/code/Magento/CheckoutAgreements/composer.json index 82032daa092e8..0306f6b14e64e 100644 --- a/app/code/Magento/CheckoutAgreements/composer.json +++ b/app/code/Magento/CheckoutAgreements/composer.json @@ -10,7 +10,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php index 9a2749469feff..d781b87555981 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php @@ -5,8 +5,11 @@ */ namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; -use Magento\Framework\App\Filesystem\DirectoryList; +use \Magento\Framework\App\Filesystem\DirectoryList; +/** + * Delete image files. + */ class DeleteFiles extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images { /** @@ -23,27 +26,39 @@ class DeleteFiles extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images */ protected $resultRawFactory; + /** + * @var \Magento\Framework\App\Filesystem\DirectoryResolver + */ + private $directoryResolver; + /** * @param \Magento\Backend\App\Action\Context $context * @param \Magento\Framework\Registry $coreRegistry * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory * @param \Magento\Framework\Controller\Result\RawFactory $resultRawFactory + * @param \Magento\Framework\App\Filesystem\DirectoryResolver|null $directoryResolver */ public function __construct( \Magento\Backend\App\Action\Context $context, \Magento\Framework\Registry $coreRegistry, \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, - \Magento\Framework\Controller\Result\RawFactory $resultRawFactory + \Magento\Framework\Controller\Result\RawFactory $resultRawFactory, + \Magento\Framework\App\Filesystem\DirectoryResolver $directoryResolver = null ) { + parent::__construct($context, $coreRegistry); + $this->resultRawFactory = $resultRawFactory; $this->resultJsonFactory = $resultJsonFactory; - parent::__construct($context, $coreRegistry); + $this->directoryResolver = $directoryResolver + ?: $this->_objectManager->get(\Magento\Framework\App\Filesystem\DirectoryResolver::class); + } /** * Delete file from media storage. * * @return \Magento\Framework\Controller\ResultInterface + * @throws \Magento\Framework\Exception\LocalizedException */ public function execute() { @@ -56,6 +71,11 @@ public function execute() /** @var $helper \Magento\Cms\Helper\Wysiwyg\Images */ $helper = $this->_objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); $path = $this->getStorage()->getSession()->getCurrentPath(); + if (!$this->directoryResolver->validatePath($path, DirectoryList::MEDIA)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('Directory %1 is not under storage root path.', $path) + ); + } foreach ($files as $file) { $file = $helper->idDecode($file); /** @var \Magento\Framework\Filesystem $filesystem */ diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolder.php b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolder.php index 8a89de87a6f85..1e8288fb00141 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolder.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolder.php @@ -6,6 +6,11 @@ */ namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; +use \Magento\Framework\App\Filesystem\DirectoryList; + +/** + * Delete image folder. + */ class DeleteFolder extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images { /** @@ -18,32 +23,48 @@ class DeleteFolder extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images */ protected $resultRawFactory; + /** + * @var \Magento\Framework\App\Filesystem\DirectoryResolver + */ + private $directoryResolver; + /** * @param \Magento\Backend\App\Action\Context $context * @param \Magento\Framework\Registry $coreRegistry * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory * @param \Magento\Framework\Controller\Result\RawFactory $resultRawFactory + * @param \Magento\Framework\App\Filesystem\DirectoryResolver|null $directoryResolver */ public function __construct( \Magento\Backend\App\Action\Context $context, \Magento\Framework\Registry $coreRegistry, \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, - \Magento\Framework\Controller\Result\RawFactory $resultRawFactory + \Magento\Framework\Controller\Result\RawFactory $resultRawFactory, + \Magento\Framework\App\Filesystem\DirectoryResolver $directoryResolver = null ) { + parent::__construct($context, $coreRegistry); + $this->resultRawFactory = $resultRawFactory; $this->resultJsonFactory = $resultJsonFactory; - parent::__construct($context, $coreRegistry); + $this->directoryResolver = $directoryResolver + ?: $this->_objectManager->get(\Magento\Framework\App\Filesystem\DirectoryResolver::class); } /** * Delete folder action * * @return \Magento\Framework\Controller\ResultInterface + * @throws \Magento\Framework\Exception\LocalizedException */ public function execute() { try { $path = $this->getStorage()->getCmsWysiwygImages()->getCurrentPath(); + if (!$this->directoryResolver->validatePath($path, DirectoryList::MEDIA)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('Directory %1 is not under storage root path.', $path) + ); + } $this->getStorage()->deleteDirectory($path); return $this->resultRawFactory->create(); } catch (\Exception $e) { diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolder.php b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolder.php index 2124bdabe6009..0f00b03ff6da5 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolder.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolder.php @@ -6,6 +6,11 @@ */ namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; +use \Magento\Framework\App\Filesystem\DirectoryList; + +/** + * Creates new folder. + */ class NewFolder extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images { /** @@ -13,24 +18,35 @@ class NewFolder extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images */ protected $resultJsonFactory; + /** + * @var \Magento\Framework\App\Filesystem\DirectoryResolver + */ + private $directoryResolver; + /** * @param \Magento\Backend\App\Action\Context $context * @param \Magento\Framework\Registry $coreRegistry * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory + * @param \Magento\Framework\App\Filesystem\DirectoryResolver|null $directoryResolver */ public function __construct( \Magento\Backend\App\Action\Context $context, \Magento\Framework\Registry $coreRegistry, - \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory + \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, + \Magento\Framework\App\Filesystem\DirectoryResolver $directoryResolver = null ) { - $this->resultJsonFactory = $resultJsonFactory; parent::__construct($context, $coreRegistry); + + $this->resultJsonFactory = $resultJsonFactory; + $this->directoryResolver = $directoryResolver + ?: $this->_objectManager->get(\Magento\Framework\App\Filesystem\DirectoryResolver::class); } /** * New folder action * * @return \Magento\Framework\Controller\ResultInterface + * @throws \Magento\Framework\Exception\LocalizedException */ public function execute() { @@ -38,6 +54,11 @@ public function execute() $this->_initAction(); $name = $this->getRequest()->getPost('name'); $path = $this->getStorage()->getSession()->getCurrentPath(); + if (!$this->directoryResolver->validatePath($path, DirectoryList::MEDIA)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('Directory %1 is not under storage root path.', $path) + ); + } $result = $this->getStorage()->createDirectory($name, $path); } catch (\Exception $e) { $result = ['error' => true, 'message' => $e->getMessage()]; diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/Upload.php b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/Upload.php index 7a94c4ab6aa12..b5cbfddcf7db9 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/Upload.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/Upload.php @@ -6,6 +6,11 @@ */ namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; +use \Magento\Framework\App\Filesystem\DirectoryList; + +/** + * Upload image. + */ class Upload extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images { /** @@ -13,31 +18,48 @@ class Upload extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images */ protected $resultJsonFactory; + /** + * @var \Magento\Framework\App\Filesystem\DirectoryResolver + */ + private $directoryResolver; + /** * @param \Magento\Backend\App\Action\Context $context * @param \Magento\Framework\Registry $coreRegistry * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory + * @param \Magento\Framework\App\Filesystem\DirectoryResolver|null $directoryResolver + * @throws \RuntimeException */ public function __construct( \Magento\Backend\App\Action\Context $context, \Magento\Framework\Registry $coreRegistry, - \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory + \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, + \Magento\Framework\App\Filesystem\DirectoryResolver $directoryResolver = null ) { - $this->resultJsonFactory = $resultJsonFactory; parent::__construct($context, $coreRegistry); + + $this->resultJsonFactory = $resultJsonFactory; + $this->directoryResolver = $directoryResolver + ?: $this->_objectManager->get(\Magento\Framework\App\Filesystem\DirectoryResolver::class); } /** * Files upload processing * * @return \Magento\Framework\Controller\ResultInterface + * @throws \Magento\Framework\Exception\LocalizedException */ public function execute() { try { $this->_initAction(); - $targetPath = $this->getStorage()->getSession()->getCurrentPath(); - $result = $this->getStorage()->uploadFile($targetPath, $this->getRequest()->getParam('type')); + $path = $this->getStorage()->getSession()->getCurrentPath(); + if (!$this->directoryResolver->validatePath($path, DirectoryList::MEDIA)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('Directory %1 is not under storage root path.', $path) + ); + } + $result = $this->getStorage()->uploadFile($path, $this->getRequest()->getParam('type')); } catch (\Exception $e) { $result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()]; } diff --git a/app/code/Magento/Cms/Helper/Wysiwyg/Images.php b/app/code/Magento/Cms/Helper/Wysiwyg/Images.php index a557e045c5ef2..a94127eafdae1 100644 --- a/app/code/Magento/Cms/Helper/Wysiwyg/Images.php +++ b/app/code/Magento/Cms/Helper/Wysiwyg/Images.php @@ -9,6 +9,8 @@ /** * Wysiwyg Images Helper + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Images extends \Magento\Framework\App\Helper\AbstractHelper { @@ -127,17 +129,23 @@ public function convertPathToId($path) } /** - * Decode HTML element id + * Decode HTML element id. * * @param string $id * @return string + * @throws \InvalidArgumentException When path contains restricted symbols. */ public function convertIdToPath($id) { if ($id === \Magento\Theme\Helper\Storage::NODE_ROOT) { return $this->getStorageRoot(); } else { - return $this->getStorageRoot() . $this->idDecode($id); + $path = $this->getStorageRoot() . $this->idDecode($id); + if (strpos($path, DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR) !== false) { + throw new \InvalidArgumentException('Path is invalid'); + } + + return $path; } } @@ -253,7 +261,7 @@ public function idEncode($string) } /** - * Revert opration to idEncode + * Revert operation to idEncode * * @param string $string * @return string diff --git a/app/code/Magento/Cms/Model/PageRepository.php b/app/code/Magento/Cms/Model/PageRepository.php index 1b20f0551f2b5..4c2468913abd8 100644 --- a/app/code/Magento/Cms/Model/PageRepository.php +++ b/app/code/Magento/Cms/Model/PageRepository.php @@ -102,7 +102,7 @@ public function __construct( */ public function save(\Magento\Cms\Api\Data\PageInterface $page) { - if (empty($page->getStoreId())) { + if ($page->getStoreId() === null) { $storeId = $this->storeManager->getStore()->getId(); $page->setStoreId($storeId); } diff --git a/app/code/Magento/Cms/Model/ResourceModel/Block/Grid/Collection.php b/app/code/Magento/Cms/Model/ResourceModel/Block/Grid/Collection.php index 7924f8039b2c2..bfd56d85b4cb2 100644 --- a/app/code/Magento/Cms/Model/ResourceModel/Block/Grid/Collection.php +++ b/app/code/Magento/Cms/Model/ResourceModel/Block/Grid/Collection.php @@ -6,7 +6,7 @@ namespace Magento\Cms\Model\ResourceModel\Block\Grid; use Magento\Framework\Api\Search\SearchResultInterface; -use Magento\Framework\Search\AggregationInterface; +use Magento\Framework\Api\Search\AggregationInterface; use Magento\Cms\Model\ResourceModel\Block\Collection as BlockCollection; /** @@ -82,6 +82,7 @@ public function getAggregations() public function setAggregations($aggregations) { $this->aggregations = $aggregations; + return $this; } /** diff --git a/app/code/Magento/Cms/Model/ResourceModel/Page/Grid/Collection.php b/app/code/Magento/Cms/Model/ResourceModel/Page/Grid/Collection.php index 01a1f83b83db9..63f5e1c83df46 100644 --- a/app/code/Magento/Cms/Model/ResourceModel/Page/Grid/Collection.php +++ b/app/code/Magento/Cms/Model/ResourceModel/Page/Grid/Collection.php @@ -83,6 +83,7 @@ public function getAggregations() public function setAggregations($aggregations) { $this->aggregations = $aggregations; + return $this; } /** diff --git a/app/code/Magento/Cms/Test/Unit/Helper/Wysiwyg/ImagesTest.php b/app/code/Magento/Cms/Test/Unit/Helper/Wysiwyg/ImagesTest.php index 21ccdea360ccc..bf7ba8932f5c6 100644 --- a/app/code/Magento/Cms/Test/Unit/Helper/Wysiwyg/ImagesTest.php +++ b/app/code/Magento/Cms/Test/Unit/Helper/Wysiwyg/ImagesTest.php @@ -77,15 +77,15 @@ protected function setUp() $this->path = 'PATH/'; $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->eventManagerMock = $this->getMock('Magento\Framework\Event\ManagerInterface', [], [], '', false); + $this->eventManagerMock = $this->getMock(\Magento\Framework\Event\ManagerInterface::class, [], [], '', false); - $this->requestMock = $this->getMock('Magento\Framework\App\RequestInterface', [], [], '', false); + $this->requestMock = $this->getMock(\Magento\Framework\App\RequestInterface::class, [], [], '', false); - $this->urlEncoderMock = $this->getMock('Magento\Framework\Url\EncoderInterface', [], [], '', false); + $this->urlEncoderMock = $this->getMock(\Magento\Framework\Url\EncoderInterface::class, [], [], '', false); - $this->backendDataMock = $this->getMock('Magento\Backend\Helper\Data', [], [], '', false); + $this->backendDataMock = $this->getMock(\Magento\Backend\Helper\Data::class, [], [], '', false); - $this->contextMock = $this->getMock('Magento\Framework\App\Helper\Context', [], [], '', false); + $this->contextMock = $this->getMock(\Magento\Framework\App\Helper\Context::class, [], [], '', false); $this->contextMock->expects($this->any()) ->method('getEventManager') ->willReturn($this->eventManagerMock); @@ -97,7 +97,7 @@ protected function setUp() ->willReturn($this->urlEncoderMock); $this->directoryWriteMock = $this->getMock( - '\Magento\Framework\Filesystem\Directory\Write', + \Magento\Framework\Filesystem\Directory\Write::class, [], ['path' => $this->path], '', @@ -112,12 +112,12 @@ protected function setUp() ] ); - $this->filesystemMock = $this->getMock('Magento\Framework\Filesystem', [], [], '', false); + $this->filesystemMock = $this->getMock(\Magento\Framework\Filesystem::class, [], [], '', false); $this->filesystemMock->expects($this->once()) ->method('getDirectoryWrite') ->willReturn($this->directoryWriteMock); - $this->storeManagerMock = $this->getMockBuilder('Magento\Store\Model\StoreManagerInterface') + $this->storeManagerMock = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class) ->setMethods( [ 'clearWebsiteCache', 'getDefaultStoreView', 'getGroup', 'getGroups', @@ -128,10 +128,10 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->storeMock = $this->getMock('Magento\Store\Model\Store', [], [], '', false); + $this->storeMock = $this->getMock(\Magento\Store\Model\Store::class, [], [], '', false); $this->imagesHelper = $this->objectManager->getObject( - 'Magento\Cms\Helper\Wysiwyg\Images', + \Magento\Cms\Helper\Wysiwyg\Images::class, [ 'context' => $this->contextMock, 'filesystem' => $this->filesystemMock, @@ -233,6 +233,15 @@ public function testConvertIdToPathNodeRoot() $this->assertEquals($this->imagesHelper->getStorageRoot(), $this->imagesHelper->convertIdToPath($pathId)); } + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Path is invalid + */ + public function testConvertIdToPathInvalid() + { + $this->imagesHelper->convertIdToPath('Ly4uLy4uLy4uLy4uLy4uL3dvcms-'); + } + /** * @param string $fileName * @param int $maxLength @@ -360,7 +369,7 @@ public function testGetCurrentPath($pathId, $expectedPath, $isExist) public function testGetCurrentPathThrowException() { $this->setExpectedException( - '\Magento\Framework\Exception\LocalizedException', + \Magento\Framework\Exception\LocalizedException::class, 'The directory PATH/wysiwyg is not writable by server.' ); diff --git a/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php b/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php index 9c894cbd4b529..6efd13716925e 100644 --- a/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php +++ b/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php @@ -113,9 +113,9 @@ class StorageTest extends \PHPUnit_Framework_TestCase */ protected function setUp() { - $this->filesystemMock = $this->getMock('Magento\Framework\Filesystem', [], [], '', false); + $this->filesystemMock = $this->getMock(\Magento\Framework\Filesystem::class, [], [], '', false); $this->driverMock = $this->getMockForAbstractClass( - 'Magento\Framework\Filesystem\DriverInterface', + \Magento\Framework\Filesystem\DriverInterface::class, [], '', false, @@ -123,114 +123,103 @@ protected function setUp() true, ['getRealPath'] ); - $this->driverMock->expects($this->any())->method('getRealPath')->will($this->returnArgument(0)); + $this->driverMock->expects($this->any())->method('getRealPath')->willReturnArgument(0); $this->directoryMock = $this->getMock( - 'Magento\Framework\Filesystem\Directory\Write', + \Magento\Framework\Filesystem\Directory\Write::class, ['delete', 'getDriver', 'create'], [], '', false ); - $this->directoryMock->expects( - $this->any() - )->method( - 'getDriver' - )->will( - $this->returnValue($this->driverMock) - ); + $this->directoryMock->expects($this->any()) + ->method('getDriver') + ->willReturn($this->driverMock); $this->filesystemMock = $this->getMock( - 'Magento\Framework\Filesystem', + \Magento\Framework\Filesystem::class, ['getDirectoryWrite'], [], '', false ); - $this->filesystemMock->expects( - $this->any() - )->method( - 'getDirectoryWrite' - )->with( - DirectoryList::MEDIA - )->will( - $this->returnValue($this->directoryMock) - ); + $this->filesystemMock->expects($this->any()) + ->method('getDirectoryWrite') + ->with(DirectoryList::MEDIA) + ->willReturn($this->directoryMock); $this->adapterFactoryMock = $this->getMock( - 'Magento\Framework\Image\AdapterFactory', + \Magento\Framework\Image\AdapterFactory::class, [], [], '', false ); $this->imageHelperMock = $this->getMock( - 'Magento\Cms\Helper\Wysiwyg\Images', + \Magento\Cms\Helper\Wysiwyg\Images::class, ['getStorageRoot'], [], '', false ); - $this->imageHelperMock->expects( - $this->any() - )->method( - 'getStorageRoot' - )->will( - $this->returnValue(self::STORAGE_ROOT_DIR) - ); + $this->imageHelperMock->expects($this->any()) + ->method('getStorageRoot') + ->willReturn(self::STORAGE_ROOT_DIR); $this->resizeParameters = ['width' => 100, 'height' => 50]; $this->storageCollectionFactoryMock = $this->getMock( - 'Magento\Cms\Model\Wysiwyg\Images\Storage\CollectionFactory', + \Magento\Cms\Model\Wysiwyg\Images\Storage\CollectionFactory::class, ['create'], [], '', false ); $this->storageFileFactoryMock = $this->getMock( - 'Magento\MediaStorage\Model\File\Storage\FileFactory', + \Magento\MediaStorage\Model\File\Storage\FileFactory::class, [], [], '', false ); $this->storageDatabaseFactoryMock = $this->getMock( - 'Magento\MediaStorage\Model\File\Storage\DatabaseFactory', + \Magento\MediaStorage\Model\File\Storage\DatabaseFactory::class, [], [], '', false ); $this->directoryDatabaseFactoryMock = $this->getMock( - 'Magento\MediaStorage\Model\File\Storage\Directory\DatabaseFactory', + \Magento\MediaStorage\Model\File\Storage\Directory\DatabaseFactory::class, ['create'], [], '', false ); $this->directoryCollectionMock = $this->getMock( - 'Magento\MediaStorage\Model\File\Storage\Directory\Database', + \Magento\MediaStorage\Model\File\Storage\Directory\Database::class, [], [], '', false ); - $this->uploaderFactoryMock = $this->getMockBuilder('Magento\MediaStorage\Model\File\UploaderFactory') + $this->uploaderFactoryMock = $this->getMockBuilder(\Magento\MediaStorage\Model\File\UploaderFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->sessionMock = $this->getMockBuilder(\Magento\Backend\Model\Session::class) ->disableOriginalConstructor() ->getMock(); - $this->sessionMock = $this->getMock('Magento\Backend\Model\Session', [], [], '', false); - $this->backendUrlMock = $this->getMock('Magento\Backend\Model\Url', [], [], '', false); + $this->backendUrlMock = $this->getMock(\Magento\Backend\Model\Url::class, [], [], '', false); - $this->coreFileStorageMock = $this->getMockBuilder('Magento\MediaStorage\Helper\File\Storage\Database') + $this->coreFileStorageMock = $this->getMockBuilder(\Magento\MediaStorage\Helper\File\Storage\Database::class) ->disableOriginalConstructor() ->getMock(); $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->imagesStorage = $this->objectManagerHelper->getObject( - 'Magento\Cms\Model\Wysiwyg\Images\Storage', + \Magento\Cms\Model\Wysiwyg\Images\Storage::class, [ 'session' => $this->sessionMock, 'backendUrl' => $this->backendUrlMock, @@ -238,7 +227,7 @@ protected function setUp() 'coreFileStorageDb' => $this->coreFileStorageMock, 'filesystem' => $this->filesystemMock, 'imageFactory' => $this->adapterFactoryMock, - 'assetRepo' => $this->getMock('Magento\Framework\View\Asset\Repository', [], [], '', false), + 'assetRepo' => $this->getMock(\Magento\Framework\View\Asset\Repository::class, [], [], '', false), 'storageCollectionFactory' => $this->storageCollectionFactoryMock, 'storageFileFactory' => $this->storageFileFactoryMock, 'storageDatabaseFactory' => $this->storageDatabaseFactoryMock, @@ -247,8 +236,8 @@ protected function setUp() 'resizeParameters' => $this->resizeParameters, 'dirs' => [ 'exclude' => [], - 'include' => [] - ] + 'include' => [], + ], ] ); } @@ -275,7 +264,7 @@ public function testGetResizeHeight() public function testDeleteDirectoryOverRoot() { $this->setExpectedException( - '\Magento\Framework\Exception\LocalizedException', + \Magento\Framework\Exception\LocalizedException::class, sprintf('Directory %s is not under storage root path.', self::INVALID_DIRECTORY_OVER_ROOT) ); $this->imagesStorage->deleteDirectory(self::INVALID_DIRECTORY_OVER_ROOT); @@ -287,7 +276,7 @@ public function testDeleteDirectoryOverRoot() public function testDeleteRootDirectory() { $this->setExpectedException( - '\Magento\Framework\Exception\LocalizedException', + \Magento\Framework\Exception\LocalizedException::class, sprintf('We can\'t delete root directory %s right now.', self::STORAGE_ROOT_DIR) ); $this->imagesStorage->deleteDirectory(self::STORAGE_ROOT_DIR); @@ -324,10 +313,10 @@ public function testGetDirsCollectionCreateSubDirectories() * @param array $expectedRemoveKeys * @dataProvider dirsCollectionDataProvider */ - public function testGetDirsCollection($exclude, $include, $fileNames, $expectedRemoveKeys) + public function testGetDirsCollection(array $exclude, array $include, array $fileNames, array $expectedRemoveKeys) { $this->imagesStorage = $this->objectManagerHelper->getObject( - 'Magento\Cms\Model\Wysiwyg\Images\Storage', + \Magento\Cms\Model\Wysiwyg\Images\Storage::class, [ 'session' => $this->sessionMock, 'backendUrl' => $this->backendUrlMock, @@ -335,7 +324,7 @@ public function testGetDirsCollection($exclude, $include, $fileNames, $expectedR 'coreFileStorageDb' => $this->coreFileStorageMock, 'filesystem' => $this->filesystemMock, 'imageFactory' => $this->adapterFactoryMock, - 'assetRepo' => $this->getMock('Magento\Framework\View\Asset\Repository', [], [], '', false), + 'assetRepo' => $this->getMock(\Magento\Framework\View\Asset\Repository::class, [], [], '', false), 'storageCollectionFactory' => $this->storageCollectionFactoryMock, 'storageFileFactory' => $this->storageFileFactoryMock, 'storageDatabaseFactory' => $this->storageDatabaseFactoryMock, @@ -344,15 +333,15 @@ public function testGetDirsCollection($exclude, $include, $fileNames, $expectedR 'resizeParameters' => $this->resizeParameters, 'dirs' => [ 'exclude' => $exclude, - 'include' => $include - ] + 'include' => $include, + ], ] ); $collection = []; foreach ($fileNames as $filename) { /** @var \Magento\Framework\DataObject|\PHPUnit_Framework_MockObject_MockObject $objectMock */ - $objectMock = $this->getMock('Magento\Framework\DataObject', ['getFilename'], [], '', false); + $objectMock = $this->getMock(\Magento\Framework\DataObject::class, ['getFilename'], [], '', false); $objectMock->expects($this->any()) ->method('getFilename') ->willReturn(self::STORAGE_ROOT_DIR . $filename); @@ -370,11 +359,11 @@ public function dirsCollectionDataProvider() return [ [ 'exclude' => [ - ['name' => 'dress'] + ['name' => 'dress'], ], 'include' => [], 'filenames' => [], - 'expectRemoveKeys' => [] + 'expectRemoveKeys' => [], ], [ 'exclude' => [], @@ -382,36 +371,36 @@ public function dirsCollectionDataProvider() 'filenames' => [ '/dress', ], - 'expectRemoveKeys' => [] + 'expectRemoveKeys' => [], ], [ 'exclude' => [ - ['name' => 'dress'] + ['name' => 'dress'], ], 'include' => [], 'filenames' => [ '/collection', ], - 'expectRemoveKeys' => [] + 'expectRemoveKeys' => [], ], [ 'exclude' => [ ['name' => 'gear', 'regexp' => 1], ['name' => 'home', 'regexp' => 1], ['name' => 'collection'], - ['name' => 'dress'] + ['name' => 'dress'], ], 'include' => [ ['name' => 'home', 'regexp' => 1], - ['name' => 'collection'] + ['name' => 'collection'], ], 'filenames' => [ '/dress', '/collection', '/gear' ], - 'expectRemoveKeys' => [[0], [2]] - ] + 'expectRemoveKeys' => [[0], [2]], + ], ]; } @@ -422,10 +411,10 @@ public function dirsCollectionDataProvider() * @param array $collectionArray * @param array $expectedRemoveKeys */ - protected function generalTestGetDirsCollection($path, $collectionArray = [], $expectedRemoveKeys = []) + protected function generalTestGetDirsCollection($path, array $collectionArray = [], array $expectedRemoveKeys = []) { /** @var StorageCollection|\PHPUnit_Framework_MockObject_MockObject $storageCollectionMock */ - $storageCollectionMock = $this->getMockBuilder('Magento\Cms\Model\Wysiwyg\Images\Storage\Collection') + $storageCollectionMock = $this->getMockBuilder(\Magento\Cms\Model\Wysiwyg\Images\Storage\Collection::class) ->disableOriginalConstructor() ->getMock(); $storageCollectionMock->expects($this->once()) diff --git a/app/code/Magento/Cms/composer.json b/app/code/Magento/Cms/composer.json index 64b88d212a834..c9f2365548fbd 100644 --- a/app/code/Magento/Cms/composer.json +++ b/app/code/Magento/Cms/composer.json @@ -18,7 +18,7 @@ "magento/module-cms-sample-data": "Sample Data version:100.1.*" }, "type": "magento2-module", - "version": "101.0.9", + "version": "101.0.11", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/CmsUrlRewrite/composer.json b/app/code/Magento/CmsUrlRewrite/composer.json index b3a85874a3faf..fdc0a52cac714 100644 --- a/app/code/Magento/CmsUrlRewrite/composer.json +++ b/app/code/Magento/CmsUrlRewrite/composer.json @@ -9,7 +9,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Config/composer.json b/app/code/Magento/Config/composer.json index 238e0c80a38ce..c996a6d97d47a 100644 --- a/app/code/Magento/Config/composer.json +++ b/app/code/Magento/Config/composer.json @@ -15,7 +15,7 @@ "magento/module-deploy": "100.1.*" }, "type": "magento2-module", - "version": "100.1.7", + "version": "100.1.8", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Config/view/adminhtml/templates/system/config/form/field/array.phtml b/app/code/Magento/Config/view/adminhtml/templates/system/config/form/field/array.phtml index 0c2045cbe5232..6ba13ad68e6ca 100644 --- a/app/code/Magento/Config/view/adminhtml/templates/system/config/form/field/array.phtml +++ b/app/code/Magento/Config/view/adminhtml/templates/system/config/form/field/array.phtml @@ -21,7 +21,7 @@ $_colspan = $block->isAddAfter() ? 2 : 1; getColumns() as $columnName => $column): ?> - Action + diff --git a/app/code/Magento/ConfigurableImportExport/Model/Import/Product/Type/Configurable.php b/app/code/Magento/ConfigurableImportExport/Model/Import/Product/Type/Configurable.php index 38cca1bee6a6a..e895a739b1736 100644 --- a/app/code/Magento/ConfigurableImportExport/Model/Import/Product/Type/Configurable.php +++ b/app/code/Magento/ConfigurableImportExport/Model/Import/Product/Type/Configurable.php @@ -246,9 +246,8 @@ protected function _getSuperAttributeId($productId, $attributeId) { if (isset($this->_productSuperAttrs["{$productId}_{$attributeId}"])) { return $this->_productSuperAttrs["{$productId}_{$attributeId}"]; - } else { - return null; } + return null; } /** diff --git a/app/code/Magento/ConfigurableImportExport/composer.json b/app/code/Magento/ConfigurableImportExport/composer.json index 542981da181fd..d4c32b905ed11 100644 --- a/app/code/Magento/ConfigurableImportExport/composer.json +++ b/app/code/Magento/ConfigurableImportExport/composer.json @@ -11,7 +11,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/ConfigurableProduct/CustomerData/ConfigurableItem.php b/app/code/Magento/ConfigurableProduct/CustomerData/ConfigurableItem.php index 0a4fc20578ed9..3a9ed653305c5 100644 --- a/app/code/Magento/ConfigurableProduct/CustomerData/ConfigurableItem.php +++ b/app/code/Magento/ConfigurableProduct/CustomerData/ConfigurableItem.php @@ -26,6 +26,7 @@ class ConfigurableItem extends DefaultItem * @param \Magento\Catalog\Helper\Product\ConfigurationPool $configurationPool * @param \Magento\Checkout\Helper\Data $checkoutHelper * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig + * @param \Magento\Framework\Escaper|null $escaper */ public function __construct( \Magento\Catalog\Helper\Image $imageHelper, @@ -33,14 +34,16 @@ public function __construct( \Magento\Framework\UrlInterface $urlBuilder, \Magento\Catalog\Helper\Product\ConfigurationPool $configurationPool, \Magento\Checkout\Helper\Data $checkoutHelper, - \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig + \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, + \Magento\Framework\Escaper $escaper = null ) { parent::__construct( $imageHelper, $msrpHelper, $urlBuilder, $configurationPool, - $checkoutHelper + $checkoutHelper, + $escaper ); $this->_scopeConfig = $scopeConfig; } diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionsProvider.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionsProvider.php index f96c943e3dc4a..f32dd43508783 100644 --- a/app/code/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionsProvider.php +++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionsProvider.php @@ -9,6 +9,8 @@ use Magento\Catalog\Model\ResourceModel\Product\LinkedProductSelectBuilderInterface; use Magento\Framework\App\ResourceConnection; use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory; +use Magento\Store\Model\StoreManagerInterface; +use Magento\Framework\App\ObjectManager; /** * Retrieve list of products where each product contains lower price than others at least for one possible price type @@ -31,7 +33,12 @@ class LowestPriceOptionsProvider implements LowestPriceOptionsProviderInterface private $collectionFactory; /** - * Key is product id. Value is prepared product collection + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * Key is product id and store id. Value is array of prepared linked products * * @var array */ @@ -41,15 +48,19 @@ class LowestPriceOptionsProvider implements LowestPriceOptionsProviderInterface * @param ResourceConnection $resourceConnection * @param LinkedProductSelectBuilderInterface $linkedProductSelectBuilder * @param CollectionFactory $collectionFactory + * @param StoreManagerInterface $storeManager */ public function __construct( ResourceConnection $resourceConnection, LinkedProductSelectBuilderInterface $linkedProductSelectBuilder, - CollectionFactory $collectionFactory + CollectionFactory $collectionFactory, + StoreManagerInterface $storeManager = null ) { $this->resource = $resourceConnection; $this->linkedProductSelectBuilder = $linkedProductSelectBuilder; $this->collectionFactory = $collectionFactory; + $this->storeManager = $storeManager + ?: ObjectManager::getInstance()->get(StoreManagerInterface::class); } /** @@ -57,16 +68,19 @@ public function __construct( */ public function getProducts(ProductInterface $product) { - if (!isset($this->productsMap[$product->getId()])) { + $key = $this->storeManager->getStore()->getId() . '-' . $product->getId(); + if (!isset($this->productsMap[$key])) { $productIds = $this->resource->getConnection()->fetchCol( '(' . implode(') UNION (', $this->linkedProductSelectBuilder->build($product->getId())) . ')' ); - $this->productsMap[$product->getId()] = $this->collectionFactory->create() - ->addAttributeToSelect(['price', 'special_price']) + $this->productsMap[$key] = $this->collectionFactory->create() + ->addAttributeToSelect( + ['price', 'special_price', 'special_from_date', 'special_to_date', 'tax_class_id'] + ) ->addIdFilter($productIds) ->getItems(); } - return $this->productsMap[$product->getId()]; + return $this->productsMap[$key]; } } diff --git a/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/Data/AssociatedProducts.php b/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/Data/AssociatedProducts.php index 530a554eb4a5d..637e30348a88f 100644 --- a/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/Data/AssociatedProducts.php +++ b/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/Data/AssociatedProducts.php @@ -17,6 +17,8 @@ use Magento\Framework\Locale\CurrencyInterface; use Magento\Framework\Json\Helper\Data as JsonHelper; use Magento\Catalog\Helper\Image as ImageHelper; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Escaper; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -83,6 +85,11 @@ class AssociatedProducts */ protected $imageHelper; + /** + * @var Escaper + */ + private $escaper; + /** * @param LocatorInterface $locator * @param UrlInterface $urlBuilder @@ -93,6 +100,8 @@ class AssociatedProducts * @param CurrencyInterface $localeCurrency * @param JsonHelper $jsonHelper * @param ImageHelper $imageHelper + * @param Escaper $escaper + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( LocatorInterface $locator, @@ -103,7 +112,8 @@ public function __construct( VariationMatrix $variationMatrix, CurrencyInterface $localeCurrency, JsonHelper $jsonHelper, - ImageHelper $imageHelper + ImageHelper $imageHelper, + Escaper $escaper = null ) { $this->locator = $locator; $this->urlBuilder = $urlBuilder; @@ -114,6 +124,7 @@ public function __construct( $this->localeCurrency = $localeCurrency; $this->jsonHelper = $jsonHelper; $this->imageHelper = $imageHelper; + $this->escaper = $escaper ?: ObjectManager::getInstance()->get(Escaper::class); } /** @@ -280,9 +291,9 @@ protected function prepareVariations() 'product_link' => '' . $product->getName() . '', - 'sku' => $product->getSku(), - 'name' => $product->getName(), + ) . '" target="_blank">' . $this->escaper->escapeHtml($product->getName()) . '', + 'sku' => $this->escaper->escapeHtml($product->getSku()), + 'name' => $this->escaper->escapeHtml($product->getName()), 'qty' => $this->getProductStockQty($product), 'price' => $currency->toCurrency(sprintf("%f", $price), ['display' => false]), 'price_string' => $currency->toCurrency(sprintf("%f", $price)), diff --git a/app/code/Magento/ConfigurableProduct/composer.json b/app/code/Magento/ConfigurableProduct/composer.json index 5d544a29485a2..1e771034969d3 100644 --- a/app/code/Magento/ConfigurableProduct/composer.json +++ b/app/code/Magento/ConfigurableProduct/composer.json @@ -23,7 +23,7 @@ "magento/module-product-links-sample-data": "Sample Data version:100.1.*" }, "type": "magento2-module", - "version": "100.1.11", + "version": "100.1.13", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Contact/composer.json b/app/code/Magento/Contact/composer.json index 401451d1f3977..628681ee2912a 100644 --- a/app/code/Magento/Contact/composer.json +++ b/app/code/Magento/Contact/composer.json @@ -10,7 +10,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Cookie/composer.json b/app/code/Magento/Cookie/composer.json index 0af97399a3e3e..3e8e4706324f6 100644 --- a/app/code/Magento/Cookie/composer.json +++ b/app/code/Magento/Cookie/composer.json @@ -10,7 +10,7 @@ "magento/module-backend": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php b/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php index 6fb10a9b765d1..08c7a80c7639d 100644 --- a/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php +++ b/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php @@ -9,7 +9,7 @@ */ namespace Magento\Cron\Observer; -use Magento\Framework\Console\CLI; +use Magento\Framework\Console\Cli; use Magento\Framework\Event\ObserverInterface; use \Magento\Cron\Model\Schedule; @@ -454,7 +454,6 @@ protected function saveSchedule($jobCode, $cronExpression, $timeInterval, $exist if ($schedule->trySchedule()) { // time matches cron expression $schedule->save(); - return; } } } diff --git a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php index 43b1cf2269504..d89ada3b9fb12 100644 --- a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php +++ b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php @@ -530,11 +530,9 @@ public function testDispatchGenerate() { $jobConfig = [ 'test_group' => [ - 'default' => [ - 'test_job1' => [ - 'instance' => 'CronJob', - 'method' => 'execute', - ], + 'test_job1' => [ + 'instance' => 'CronJob', + 'method' => 'execute', ], ], ]; @@ -542,11 +540,9 @@ public function testDispatchGenerate() $this->_config->expects($this->at(0))->method('getJobs')->will($this->returnValue($jobConfig)); $jobs = [ 'test_group' => [ - 'default' => [ - 'job1' => ['config_path' => 'test/path'], - 'job2' => ['schedule' => ''], - 'job3' => ['schedule' => '* * * * *'], - ], + 'job1' => ['config_path' => 'test/path'], + 'job2' => ['schedule' => ''], + 'job3' => ['schedule' => '* * * * *'], ], ]; $this->_config->expects($this->at(1))->method('getJobs')->will($this->returnValue($jobs)); @@ -570,32 +566,40 @@ public function testDispatchGenerate() $this->returnValue(time() + 10000000) ); - $this->_scopeConfig->expects($this->at(0))->method('getValue')->will($this->returnValue(0)); + $this->_scopeConfig->expects($this->any())->method('getValue')->willReturnMap( + [ + [ + 'system/cron/test_group/schedule_generate_every', + \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + null, + 0 + ], + [ + 'system/cron/test_group/schedule_ahead_for', + \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + null, + 2 + ] + ] + ); - $scheduleMethods = ['getJobCode', 'getScheduledAt', 'trySchedule', 'unsScheduleId', 'save', '__wakeup']; $schedule = $this->getMockBuilder( 'Magento\Cron\Model\Schedule' )->setMethods( - $scheduleMethods + ['getJobCode', 'getScheduledAt', 'trySchedule', 'unsScheduleId', 'save', '__wakeup', 'getCollection'] )->disableOriginalConstructor()->getMock(); $schedule->expects($this->any())->method('getJobCode')->will($this->returnValue('job_code1')); $schedule->expects($this->once())->method('getScheduledAt')->will($this->returnValue('* * * * *')); $schedule->expects($this->any())->method('unsScheduleId')->will($this->returnSelf()); $schedule->expects($this->any())->method('trySchedule')->will($this->returnSelf()); + $schedule->expects($this->any())->method('getCollection')->willReturn($this->_collection); + $schedule->expects($this->atLeastOnce())->method('save')->willReturnSelf(); $this->_collection->addItem(new \Magento\Framework\DataObject()); $this->_collection->addItem($schedule); $this->_cache->expects($this->any())->method('save'); - $scheduleMock = $this->getMockBuilder( - 'Magento\Cron\Model\Schedule' - )->disableOriginalConstructor()->setMethods( - ['getCollection', '__wakeup'] - )->getMock(); - $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection)); - $this->_scheduleFactory->expects($this->any())->method('create')->will($this->returnValue($scheduleMock)); - $this->_scheduleFactory->expects($this->any())->method('create')->will($this->returnValue($schedule)); $this->_observer->execute($this->observer); diff --git a/app/code/Magento/Cron/composer.json b/app/code/Magento/Cron/composer.json index e6a3d74dd06d3..72ea22c1abf56 100644 --- a/app/code/Magento/Cron/composer.json +++ b/app/code/Magento/Cron/composer.json @@ -10,7 +10,7 @@ "magento/module-config": "100.1.*" }, "type": "magento2-module", - "version": "100.1.4", + "version": "100.1.5", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/CurrencySymbol/composer.json b/app/code/Magento/CurrencySymbol/composer.json index b49a56e4baa8b..29d3ce3a25392 100644 --- a/app/code/Magento/CurrencySymbol/composer.json +++ b/app/code/Magento/CurrencySymbol/composer.json @@ -11,7 +11,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Customer/Controller/Account/Index.php b/app/code/Magento/Customer/Controller/Account/Index.php index f734660fc3a77..2ecf79d35b11f 100644 --- a/app/code/Magento/Customer/Controller/Account/Index.php +++ b/app/code/Magento/Customer/Controller/Account/Index.php @@ -35,9 +35,6 @@ public function __construct( */ public function execute() { - /** @var \Magento\Framework\View\Result\Page $resultPage */ - $resultPage = $this->resultPageFactory->create(); - $resultPage->getConfig()->getTitle()->set(__('My Account')); - return $resultPage; + return $this->resultPageFactory->create(); } } diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Viewfile.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Viewfile.php index 0722bb6c2a957..3c1610f7f1a26 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Viewfile.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Viewfile.php @@ -132,30 +132,18 @@ public function __construct( */ public function execute() { - $file = null; - $plain = false; - if ($this->getRequest()->getParam('file')) { - // download file - $file = $this->urlDecoder->decode( - $this->getRequest()->getParam('file') - ); - } elseif ($this->getRequest()->getParam('image')) { - // show plain image - $file = $this->urlDecoder->decode( - $this->getRequest()->getParam('image') - ); - $plain = true; - } else { - throw new NotFoundException(__('Page not found.')); - } + list($file, $plain) = $this->getFileParams(); /** @var \Magento\Framework\Filesystem $filesystem */ - $filesystem = $this->_objectManager->get('Magento\Framework\Filesystem'); + $filesystem = $this->_objectManager->get(\Magento\Framework\Filesystem::class); $directory = $filesystem->getDirectoryRead(DirectoryList::MEDIA); $fileName = CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER . '/' . ltrim($file, '/'); $path = $directory->getAbsolutePath($fileName); - if (!$directory->isFile($fileName) - && !$this->_objectManager->get('Magento\MediaStorage\Helper\File\Storage')->processStorageFile($path) + if (mb_strpos($path, '..') !== false + || (!$directory->isFile($fileName) + && !$this->_objectManager->get( + \Magento\MediaStorage\Helper\File\Storage::class + )->processStorageFile($path)) ) { throw new NotFoundException(__('Page not found.')); } @@ -198,4 +186,29 @@ public function execute() ); } } + + /** + * Get parameters from request. + * + * @return array + * @throws NotFoundException + */ + private function getFileParams() + { + if ($this->getRequest()->getParam('file')) { + // download file + $file = $this->urlDecoder->decode( + $this->getRequest()->getParam('file') + ); + return [$file, false]; + } elseif ($this->getRequest()->getParam('image')) { + // show plain image + $file = $this->urlDecoder->decode( + $this->getRequest()->getParam('image') + ); + return [$file, true]; + } else { + throw new NotFoundException(__('Page not found.')); + } + } } diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php index a13a224ec8695..1b309635e329d 100644 --- a/app/code/Magento/Customer/Model/AccountManagement.php +++ b/app/code/Magento/Customer/Model/AccountManagement.php @@ -46,6 +46,9 @@ use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; use Psr\Log\LoggerInterface as PsrLogger; +use Magento\Framework\Session\SessionManagerInterface; +use Magento\Framework\Session\SaveHandlerInterface; +use Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory; /** * Handle various customer account actions @@ -237,6 +240,21 @@ class AccountManagement implements AccountManagementInterface */ private $transportBuilder; + /** + * @var SessionManagerInterface + */ + private $sessionManager; + + /** + * @var SaveHandlerInterface + */ + private $saveHandler; + + /** + * @var CollectionFactory + */ + private $visitorCollectionFactory; + /** * @var DataObjectProcessor */ @@ -317,6 +335,9 @@ class AccountManagement implements AccountManagementInterface * @param ObjectFactory $objectFactory * @param ExtensibleDataObjectConverter $extensibleDataObjectConverter * @param DateTimeFactory $dateTimeFactory + * @param SessionManagerInterface|null $sessionManager + * @param SaveHandlerInterface|null $saveHandler + * @param CollectionFactory|null $visitorCollectionFactory * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -343,7 +364,10 @@ public function __construct( CustomerModel $customerModel, ObjectFactory $objectFactory, ExtensibleDataObjectConverter $extensibleDataObjectConverter, - DateTimeFactory $dateTimeFactory = null + DateTimeFactory $dateTimeFactory = null, + SessionManagerInterface $sessionManager = null, + SaveHandlerInterface $saveHandler = null, + CollectionFactory $visitorCollectionFactory = null ) { $this->customerFactory = $customerFactory; $this->eventManager = $eventManager; @@ -369,6 +393,12 @@ public function __construct( $this->objectFactory = $objectFactory; $this->extensibleDataObjectConverter = $extensibleDataObjectConverter; $this->dateTimeFactory = $dateTimeFactory ?: ObjectManager::getInstance()->get(DateTimeFactory::class); + $this->sessionManager = $sessionManager + ?: ObjectManager::getInstance()->get(SessionManagerInterface::class); + $this->saveHandler = $saveHandler + ?: ObjectManager::getInstance()->get(SaveHandlerInterface::class); + $this->visitorCollectionFactory = $visitorCollectionFactory + ?: ObjectManager::getInstance()->get(CollectionFactory::class); } /** @@ -523,7 +553,8 @@ public function initiatePasswordReset($email, $template, $websiteId = null) default: throw new InputException( __( - 'Invalid value of "%value" provided for the %fieldName field. Possible values are %template1 or %template2.', + 'Invalid value of "%value" provided for the %fieldName field. ' . + 'Possible values are %template1 or %template2.', [ 'value' => $template, 'fieldName' => 'template', @@ -555,7 +586,10 @@ public function resetPassword($email, $resetToken, $newPassword) $customerSecure->setRpToken(null); $customerSecure->setRpTokenCreatedAt(null); $customerSecure->setPasswordHash($this->createPasswordHash($newPassword)); + $this->sessionManager->destroy(); + $this->destroyCustomerSessions($customer->getId()); $this->customerRepository->save($customer); + return true; } @@ -842,7 +876,9 @@ private function changePasswordForCustomer($customer, $currentPassword, $newPass $customerSecure->setRpTokenCreatedAt(null); $this->checkPasswordStrength($newPassword); $customerSecure->setPasswordHash($this->createPasswordHash($newPassword)); + $this->destroyCustomerSessions($customer->getId()); $this->customerRepository->save($customer); + return true; } @@ -1301,7 +1337,7 @@ protected function getFullCustomerObject($customer) // object passed for events $mergedCustomerData = $this->customerRegistry->retrieveSecureData($customer->getId()); $customerData = - $this->dataProcessor->buildOutputDataArray($customer, '\Magento\Customer\Api\Data\CustomerInterface'); + $this->dataProcessor->buildOutputDataArray($customer, \Magento\Customer\Api\Data\CustomerInterface::class); $mergedCustomerData->addData($customerData); $mergedCustomerData->setData('name', $this->customerViewHelper->getCustomerName($customer)); return $mergedCustomerData; @@ -1334,4 +1370,35 @@ private function getEmailNotification() return $this->emailNotification; } } + + /** + * Destroy all active customer sessions by customer id (current session will not be destroyed). + * Customer sessions which should be deleted are collecting from the "customer_visitor" table considering + * configured session lifetime. + * + * @param string|int $customerId + * @return void + */ + private function destroyCustomerSessions($customerId) + { + $sessionLifetime = $this->scopeConfig->getValue( + \Magento\Framework\Session\Config::XML_PATH_COOKIE_LIFETIME, + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + $dateTime = $this->dateTimeFactory->create(); + $activeSessionsTime = $dateTime->setTimestamp($dateTime->getTimestamp() - $sessionLifetime) + ->format(DateTime::DATETIME_PHP_FORMAT); + /** @var \Magento\Customer\Model\ResourceModel\Visitor\Collection $visitorCollection */ + $visitorCollection = $this->visitorCollectionFactory->create(); + $visitorCollection->addFieldToFilter('customer_id', $customerId); + $visitorCollection->addFieldToFilter('last_visit_at', ['from' => $activeSessionsTime]); + $visitorCollection->addFieldToFilter('session_id', ['neq' => $this->sessionManager->getSessionId()]); + /** @var \Magento\Customer\Model\Visitor $visitor */ + foreach ($visitorCollection->getItems() as $visitor) { + $sessionId = $visitor->getSessionId(); + $this->sessionManager->start(); + $this->saveHandler->destroy($sessionId); + $this->sessionManager->writeClose(); + } + } } diff --git a/app/code/Magento/Customer/Model/Address/AbstractAddress.php b/app/code/Magento/Customer/Model/Address/AbstractAddress.php index 6c568148c9f1c..352d2a803cd18 100644 --- a/app/code/Magento/Customer/Model/Address/AbstractAddress.php +++ b/app/code/Magento/Customer/Model/Address/AbstractAddress.php @@ -263,7 +263,7 @@ public function setData($key, $value = null) { if (is_array($key)) { $key = $this->_implodeArrayField($key); - } elseif (is_array($value) && !empty($value) && $this->isAddressMultilineAttribute($key)) { + } elseif (is_array($value) && $this->isAddressMultilineAttribute($key)) { $value = $this->_implodeArrayValues($value); } return parent::setData($key, $value); @@ -303,7 +303,11 @@ protected function _implodeArrayField(array $data) */ protected function _implodeArrayValues($value) { - if (is_array($value) && count($value)) { + if (is_array($value)) { + if (!count($value)) { + return ''; + } + $isScalar = false; foreach ($value as $val) { if (is_scalar($val)) { diff --git a/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php b/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php index 4137ec3740ded..b1c54a1f01260 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php +++ b/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php @@ -84,7 +84,7 @@ public function __construct( $this->addressFactory = $addressFactory; $this->addressRegistry = $addressRegistry; $this->customerRegistry = $customerRegistry; - $this->addressResource = $addressResourceModel; + $this->addressResourceModel = $addressResourceModel; $this->directoryData = $directoryData; $this->addressSearchResultsFactory = $addressSearchResultsFactory; $this->addressCollectionFactory = $addressCollectionFactory; @@ -219,7 +219,7 @@ public function delete(\Magento\Customer\Api\Data\AddressInterface $address) $address = $this->addressRegistry->retrieve($addressId); $customerModel = $this->customerRegistry->retrieve($address->getCustomerId()); $customerModel->getAddressesCollection()->clear(); - $this->addressResource->delete($address); + $this->addressResourceModel->delete($address); $this->addressRegistry->remove($addressId); return true; } @@ -237,7 +237,7 @@ public function deleteById($addressId) $address = $this->addressRegistry->retrieve($addressId); $customerModel = $this->customerRegistry->retrieve($address->getCustomerId()); $customerModel->getAddressesCollection()->clear(); - $this->addressResource->delete($address); + $this->addressResourceModel->delete($address); $this->addressRegistry->remove($addressId); return true; } @@ -285,24 +285,53 @@ private function _validate(CustomerAddressModel $customerAddressModel) $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'postcode'])); } - if (!\Zend_Validate::is($customerAddressModel->getCountryId(), 'NotEmpty')) { + $countryId = (string)$customerAddressModel->getCountryId(); + if (!\Zend_Validate::is($countryId, 'NotEmpty')) { $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'countryId'])); - } + } else { + //Checking if such country exists. + if (!in_array($countryId, $this->directoryData->getCountryCollection()->getAllIds(), true)) { + $exception->addError( + __( + 'Invalid value of "%value" provided for the %fieldName field.', + [ + 'fieldName' => 'countryId', + 'value' => htmlspecialchars($countryId) + ] + ) + ); + } else { + //If country is valid then validating selected region ID. + $countryModel = $customerAddressModel->getCountryModel(); + $regionCollection = $countryModel->getRegionCollection(); + $region = $customerAddressModel->getRegion(); + $regionId = (string)$customerAddressModel->getRegionId(); + $allowedRegions = $regionCollection->getAllIds(); + $isRegionRequired = $this->directoryData->isRegionRequired($countryId); - if ($this->directoryData->isRegionRequired($customerAddressModel->getCountryId())) { - $regionCollection = $customerAddressModel->getCountryModel()->getRegionCollection(); - if (!$regionCollection->count() && empty($customerAddressModel->getRegion())) { - $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'region'])); - } elseif ( - $regionCollection->count() - && !in_array( - $customerAddressModel->getRegionId(), - array_column($regionCollection->getData(), 'region_id') - ) - ) { - $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'regionId'])); + if ($isRegionRequired && empty($allowedRegions) && !\Zend_Validate::is($region, 'NotEmpty')) { + //If region is required for country and country doesn't provide regions list + //region must be provided. + $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'region'])); + } elseif ($isRegionRequired && $allowedRegions && !\Zend_Validate::is($regionId, 'NotEmpty')) { + //If country actually has regions and requires you to + //select one then it must be selected. + $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'regionId'])); + } elseif ($regionId && !in_array($regionId, $allowedRegions, true)) { + //If a region is selected then checking if it exists. + $exception->addError( + __( + 'Invalid value of "%value" provided for the %fieldName field.', + [ + 'fieldName' => 'regionId', + 'value' => htmlspecialchars($regionId) + ] + ) + ); + } } } + return $exception; } } diff --git a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php index 3a7ec4fbecef6..b3f18ee2b2a9c 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php +++ b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php @@ -186,6 +186,13 @@ public function save(\Magento\Customer\Api\Data\CustomerInterface $customer, $pa $customerModel->setRpTokenCreatedAt(null); } + // Set group id to current stored id if no group id passed. + if (!($prevCustomerData === null) && $prevCustomerData->getGroupId() && $customer->getGroupId() === null) { + $customerModel->setGroupId( + $prevCustomerData->getGroupId() + ); + } + $this->setDefaultBilling($customerArr, $prevCustomerDataArr, $customerModel); $this->setDefaultShipping($customerArr, $prevCustomerDataArr, $customerModel); diff --git a/app/code/Magento/Customer/Model/Visitor.php b/app/code/Magento/Customer/Model/Visitor.php index ba5d09881b911..5898ae112d445 100644 --- a/app/code/Magento/Customer/Model/Visitor.php +++ b/app/code/Magento/Customer/Model/Visitor.php @@ -151,6 +151,9 @@ public function initByRequest($observer) if ($this->session->getVisitorData()) { $this->setData($this->session->getVisitorData()); + if ($this->getSessionId() != $this->session->getSessionId()) { + $this->setSessionId($this->session->getSessionId()); + } } $this->setLastVisitAt((new \DateTime())->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT)); diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ViewfileTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ViewfileTest.php index a985928f590bc..0da57e0031a12 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ViewfileTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ViewfileTest.php @@ -69,29 +69,29 @@ class ViewfileTest extends \PHPUnit_Framework_TestCase protected function setUp() { $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->requestMock = $this->getMock('Magento\Framework\App\RequestInterface', [], [], '', false); - $this->responseMock = $this->getMock('Magento\Framework\App\ResponseInterface', [], [], '', false); + $this->requestMock = $this->getMock(\Magento\Framework\App\RequestInterface::class, [], [], '', false); + $this->responseMock = $this->getMock(\Magento\Framework\App\ResponseInterface::class, [], [], '', false); $this->directoryMock = $this->getMock( - 'Magento\Framework\Filesystem\Directory\ReadInterface', + \Magento\Framework\Filesystem\Directory\ReadInterface::class, [], [], '', false ); - $this->fileSystemMock = $this->getMock('Magento\Framework\Filesystem', [], [], '', false); - $this->storage = $this->getMock('Magento\MediaStorage\Helper\File\Storage', [], [], '', false); - $this->objectManagerMock = $this->getMock('Magento\Framework\ObjectManagerInterface', [], [], '', false); + $this->fileSystemMock = $this->getMock(\Magento\Framework\Filesystem::class, [], [], '', false); + $this->storage = $this->getMock(\Magento\MediaStorage\Helper\File\Storage::class, [], [], '', false); + $this->objectManagerMock = $this->getMock(\Magento\Framework\ObjectManagerInterface::class, [], [], '', false); - $this->contextMock = $this->getMock('Magento\Backend\App\Action\Context', [], [], '', false); + $this->contextMock = $this->getMock(\Magento\Backend\App\Action\Context::class, [], [], '', false); $this->contextMock->expects($this->any())->method('getRequest')->willReturn($this->requestMock); $this->contextMock->expects($this->any())->method('getResponse')->willReturn($this->responseMock); $this->contextMock->expects($this->any())->method('getObjectManager')->willReturn($this->objectManagerMock); - $this->urlDecoderMock = $this->getMock('Magento\Framework\Url\DecoderInterface', [], [], '', false); - $this->resultRawMock = $this->getMock('Magento\Framework\Controller\Result\Raw', [], [], '', false); + $this->urlDecoderMock = $this->getMock(\Magento\Framework\Url\DecoderInterface::class, [], [], '', false); + $this->resultRawMock = $this->getMock(\Magento\Framework\Controller\Result\Raw::class, [], [], '', false); $this->resultRawFactoryMock = $this->getMock( - 'Magento\Framework\Controller\Result\RawFactory', + \Magento\Framework\Controller\Result\RawFactory::class, ['create'], [], '', @@ -106,7 +106,50 @@ protected function setUp() public function testExecuteNoParamsShouldThrowException() { /** @var \Magento\Customer\Controller\Adminhtml\Index\Viewfile $controller */ - $controller = $this->objectManager->getObject('Magento\Customer\Controller\Adminhtml\Index\Viewfile'); + $controller = $this->objectManager->getObject(\Magento\Customer\Controller\Adminhtml\Index\Viewfile::class); + $controller->execute(); + } + + /** + * @expectedException \Magento\Framework\Exception\NotFoundException + * @expectedExceptionMessage Page not found. + */ + public function testExecuteInvaliFile() + { + $file = '../../../app/etc/env.php'; + $decodedFile = base64_encode($file); + $fileName = 'customer/' . $file; + $path = 'path'; + + $this->requestMock->expects($this->atLeastOnce())->method('getParam')->with('file')->willReturn($decodedFile); + + $this->directoryMock->expects($this->once())->method('getAbsolutePath')->with($fileName)->willReturn($path); + + $this->fileSystemMock->expects($this->once())->method('getDirectoryRead') + ->with(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA) + ->willReturn($this->directoryMock); + + $this->storage->expects($this->once())->method('processStorageFile')->with($path)->willReturn(false); + + $this->objectManagerMock->expects($this->any())->method('get') + ->willReturnMap( + [ + [\Magento\Framework\Filesystem::class, $this->fileSystemMock], + [\Magento\MediaStorage\Helper\File\Storage::class, $this->storage], + ] + ); + + $this->urlDecoderMock->expects($this->once())->method('decode')->with($decodedFile)->willReturn($file); + $fileFactoryMock = $this->getMock(\Magento\Framework\App\Response\Http\FileFactory::class, [], [], '', false); + + $controller = $this->objectManager->getObject( + \Magento\Customer\Controller\Adminhtml\Index\Viewfile::class, + [ + 'context' => $this->contextMock, + 'urlDecoder' => $this->urlDecoderMock, + 'fileFactory' => $fileFactoryMock, + ] + ); $controller->execute(); } @@ -130,15 +173,15 @@ public function testExecuteParamFile() $this->objectManagerMock->expects($this->any())->method('get') ->willReturnMap( [ - ['Magento\Framework\Filesystem', $this->fileSystemMock], - ['Magento\MediaStorage\Helper\File\Storage', $this->storage] + [\Magento\Framework\Filesystem::class, $this->fileSystemMock], + [\Magento\MediaStorage\Helper\File\Storage::class, $this->storage], ] ); $this->urlDecoderMock->expects($this->once())->method('decode')->with($decodedFile)->willReturn($file); - $fileResponse = $this->getMock('Magento\Framework\App\ResponseInterface', [], [], '', false); - $fileFactoryMock = $this->getMock('Magento\Framework\App\Response\Http\FileFactory', [], [], '', false); + $fileResponse = $this->getMock(\Magento\Framework\App\ResponseInterface::class, [], [], '', false); + $fileFactoryMock = $this->getMock(\Magento\Framework\App\Response\Http\FileFactory::class, [], [], '', false); $fileFactoryMock->expects($this->once())->method('create')->with( $path, ['type' => 'filename', 'value' => $fileName], @@ -147,11 +190,11 @@ public function testExecuteParamFile() /** @var \Magento\Customer\Controller\Adminhtml\Index\Viewfile $controller */ $controller = $this->objectManager->getObject( - 'Magento\Customer\Controller\Adminhtml\Index\Viewfile', + \Magento\Customer\Controller\Adminhtml\Index\Viewfile::class, [ 'context' => $this->contextMock, 'urlDecoder' => $this->urlDecoderMock, - 'fileFactory' => $fileFactoryMock + 'fileFactory' => $fileFactoryMock, ] ); $controller->execute(); @@ -180,8 +223,8 @@ public function testExecuteGetParamImage() $this->objectManagerMock->expects($this->any())->method('get') ->willReturnMap( [ - ['Magento\Framework\Filesystem', $this->fileSystemMock], - ['Magento\MediaStorage\Helper\File\Storage', $this->storage] + [\Magento\Framework\Filesystem::class, $this->fileSystemMock], + [\Magento\MediaStorage\Helper\File\Storage::class, $this->storage], ] ); @@ -199,7 +242,7 @@ public function testExecuteGetParamImage() ); $this->resultRawFactoryMock = $this->getMock( - 'Magento\Framework\Controller\Result\RawFactory', + \Magento\Framework\Controller\Result\RawFactory::class, ['create'], [], '', @@ -209,11 +252,11 @@ public function testExecuteGetParamImage() /** @var \Magento\Customer\Controller\Adminhtml\Index\Viewfile $controller */ $controller = $this->objectManager->getObject( - 'Magento\Customer\Controller\Adminhtml\Index\Viewfile', + \Magento\Customer\Controller\Adminhtml\Index\Viewfile::class, [ 'context' => $this->contextMock, 'urlDecoder' => $this->urlDecoderMock, - 'resultRawFactory' => $this->resultRawFactoryMock + 'resultRawFactory' => $this->resultRawFactoryMock, ] ); $this->assertSame($this->resultRawMock, $controller->execute()); diff --git a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php index 88553a1ed9af0..e977197d5e9a9 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php @@ -120,6 +120,21 @@ class AccountManagementTest extends \PHPUnit_Framework_TestCase */ private $dateTimeFactory; + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Session\SessionManagerInterface + */ + private $sessionManager; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory + */ + private $visitorCollectionFactory; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Session\SaveHandlerInterface + */ + private $saveHandler; + /** * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ @@ -150,7 +165,9 @@ protected function setUp() $this->customerMetadata = $this->getMock(\Magento\Customer\Api\CustomerMetadataInterface::class); $this->customerRegistry = $this->getMock(\Magento\Customer\Model\CustomerRegistry::class, [], [], '', false); $this->logger = $this->getMock(\Psr\Log\LoggerInterface::class); - $this->encryptor = $this->getMock(\Magento\Framework\Encryption\EncryptorInterface::class); + $this->encryptor = $this->getMockBuilder(\Magento\Framework\Encryption\EncryptorInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); $this->share = $this->getMock(\Magento\Customer\Model\Config\Share::class, [], [], '', false); $this->string = $this->getMock(\Magento\Framework\Stdlib\StringUtils::class); $this->customerRepository = $this->getMock(\Magento\Customer\Api\CustomerRepositoryInterface::class); @@ -191,6 +208,20 @@ protected function setUp() ->getMock(); $this->customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) + ->setMethods(['setRpToken', 'addData', 'setRpTokenCreatedAt', 'setData', 'getPasswordHash']) + ->disableOriginalConstructor() + ->getMock(); + + $this->visitorCollectionFactory = $this->getMockBuilder( + \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class + ) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->sessionManager = $this->getMockBuilder(\Magento\Framework\Session\SessionManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->saveHandler = $this->getMockBuilder(\Magento\Framework\Session\SaveHandlerInterface::class) ->disableOriginalConstructor() ->getMock(); @@ -224,6 +255,9 @@ protected function setUp() 'objectFactory' => $this->objectFactory, 'extensibleDataObjectConverter' => $this->extensibleDataObjectConverter, 'dateTimeFactory' => $this->dateTimeFactory, + 'sessionManager' => $this->sessionManager, + 'saveHandler' => $this->saveHandler, + 'visitorCollectionFactory' => $this->visitorCollectionFactory, ] ); $reflection = new \ReflectionClass(get_class($this->accountManagement)); @@ -753,7 +787,7 @@ public function testCreateAccountWithPasswordInputException( ); } - $customer = $this->getMockBuilder('Magento\Customer\Api\Data\CustomerInterface')->getMock(); + $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); $this->accountManagement->createAccount($customer, $password); } @@ -967,7 +1001,7 @@ public function testSendPasswordReminderEmail() $this->dataObjectProcessor->expects($this->once()) ->method('buildOutputDataArray') - ->with($customer, '\Magento\Customer\Api\Data\CustomerInterface') + ->with($customer, \Magento\Customer\Api\Data\CustomerInterface::class) ->willReturn($customerData); $this->customerViewHelper->expects($this->any()) @@ -1112,7 +1146,7 @@ protected function prepareInitiatePasswordReset($email, $templateIdentifier, $se $this->dataObjectProcessor->expects($this->any()) ->method('buildOutputDataArray') - ->with($customer, '\Magento\Customer\Api\Data\CustomerInterface') + ->with($customer, \Magento\Customer\Api\Data\CustomerInterface::class) ->willReturn($customerData); $this->prepareEmailSend($email, $templateIdentifier, $sender, $storeId, $customerName); @@ -1296,27 +1330,73 @@ private function reInitModel() { $this->customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) ->disableOriginalConstructor() - ->setMethods(['getRpToken', 'getRpTokenCreatedAt']) + ->setMethods( + [ + 'getRpToken', + 'getRpTokenCreatedAt', + 'getPasswordHash', + 'setPasswordHash', + 'setRpToken', + 'setRpTokenCreatedAt', + ] + ) ->getMock(); - $this->customerSecure ->expects($this->any()) ->method('getRpToken') ->willReturn('newStringToken'); - $pastDateTime = '2016-10-25 00:00:00'; - $this->customerSecure ->expects($this->any()) ->method('getRpTokenCreatedAt') ->willReturn($pastDateTime); - $this->customer = $this->getMockBuilder(\Magento\Customer\Model\Customer::class) ->disableOriginalConstructor() ->setMethods(['getResetPasswordLinkExpirationPeriod']) ->getMock(); - $this->prepareDateTimeFactory(); + $this->sessionManager = $this->getMockBuilder(\Magento\Framework\Session\SessionManagerInterface::class) + ->disableOriginalConstructor() + ->setMethods(['destroy', 'start', 'writeClose']) + ->getMockForAbstractClass(); + $this->visitorCollectionFactory = $this->getMockBuilder( + \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class + ) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->saveHandler = $this->getMockBuilder(\Magento\Framework\Session\SaveHandlerInterface::class) + ->disableOriginalConstructor() + ->setMethods(['destroy']) + ->getMockForAbstractClass(); + + $dateTime = '2017-10-25 18:57:08'; + $timestamp = '1508983028'; + $dateTimeMock = $this->getMockBuilder(\DateTime::class) + ->disableOriginalConstructor() + ->setMethods(['format', 'getTimestamp', 'setTimestamp']) + ->getMock(); + + $dateTimeMock->expects($this->any()) + ->method('format') + ->with(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT) + ->willReturn($dateTime); + + $dateTimeMock + ->expects($this->any()) + ->method('getTimestamp') + ->willReturn($timestamp); + + $dateTimeMock + ->expects($this->any()) + ->method('setTimestamp') + ->willReturnSelf(); + + $dateTimeFactory = $this->getMockBuilder(DateTimeFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $dateTimeFactory->expects($this->any())->method('create')->willReturn($dateTimeMock); $this->objectManagerHelper = new ObjectManagerHelper($this); $this->accountManagement = $this->objectManagerHelper->getObject( @@ -1326,7 +1406,16 @@ private function reInitModel() 'customerRegistry' => $this->customerRegistry, 'customerRepository' => $this->customerRepository, 'customerModel' => $this->customer, - 'dateTimeFactory' => $this->dateTimeFactory, + 'dateTimeFactory' => $dateTimeFactory, + 'stringHelper' => $this->string, + 'scopeConfig' => $this->scopeConfig, + 'sessionManager' => $this->sessionManager, + 'visitorCollectionFactory' => $this->visitorCollectionFactory, + 'saveHandler' => $this->saveHandler, + 'encryptor' => $this->encryptor, + 'dataProcessor' => $this->dataObjectProcessor, + 'storeManager' => $this->storeManager, + 'transportBuilder' => $this->transportBuilder, ] ); $reflection = new \ReflectionClass(get_class($this->accountManagement)); @@ -1346,6 +1435,7 @@ public function testChangePassword() $newPassword = 'abcdefg'; $passwordHash = '1a2b3f4c'; + $this->reInitModel(); $this->prepareDateTimeFactory(); $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) @@ -1363,25 +1453,20 @@ public function testChangePassword() $this->authenticationMock->expects($this->once()) ->method('authenticate'); - $customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) - ->setMethods(['setRpToken', 'setRpTokenCreatedAt', 'getPasswordHash']) - ->disableOriginalConstructor() - ->getMock(); - $customerSecure->expects($this->once()) + $this->customerSecure->expects($this->once()) ->method('setRpToken') ->with(null); - $customerSecure->expects($this->once()) + $this->customerSecure->expects($this->once()) ->method('setRpTokenCreatedAt') - ->with(null) ->willReturnSelf(); - $customerSecure->expects($this->any()) + $this->customerSecure->expects($this->any()) ->method('getPasswordHash') ->willReturn($passwordHash); $this->customerRegistry->expects($this->any()) ->method('retrieveSecureData') ->with($customerId) - ->willReturn($customerSecure); + ->willReturn($this->customerSecure); $this->scopeConfig->expects($this->any()) ->method('getValue') @@ -1411,9 +1496,85 @@ public function testChangePassword() ->method('save') ->with($customer); + $this->sessionManager->expects($this->atLeastOnce())->method('start'); + $this->sessionManager->expects($this->atLeastOnce())->method('writeClose'); + $this->sessionManager->expects($this->atLeastOnce())->method('getSessionId'); + + $visitor = $this->getMockBuilder(\Magento\Customer\Model\Visitor::class) + ->disableOriginalConstructor() + ->setMethods(['getSessionId']) + ->getMock(); + $visitor->expects($this->at(0))->method('getSessionId')->willReturn('session_id_1'); + $visitor->expects($this->at(1))->method('getSessionId')->willReturn('session_id_2'); + $visitorCollection = $this->getMockBuilder( + \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class + ) + ->disableOriginalConstructor()->setMethods(['addFieldToFilter', 'getItems'])->getMock(); + $visitorCollection->expects($this->atLeastOnce())->method('addFieldToFilter')->willReturnSelf(); + $visitorCollection->expects($this->atLeastOnce())->method('getItems')->willReturn([$visitor, $visitor]); + $this->visitorCollectionFactory->expects($this->atLeastOnce())->method('create') + ->willReturn($visitorCollection); + $this->saveHandler->expects($this->at(0))->method('destroy')->with('session_id_1'); + $this->saveHandler->expects($this->at(1))->method('destroy')->with('session_id_2'); + $this->assertTrue($this->accountManagement->changePassword($email, $currentPassword, $newPassword)); } + public function testResetPassword() + { + $customerEmail = 'customer@example.com'; + $customerId = '1'; + $resetToken = 'newStringToken'; + $newPassword = 'new_password'; + + $this->reInitModel(); + $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); + $customer->expects($this->any())->method('getId')->willReturn($customerId); + $this->customerRepository->expects($this->atLeastOnce())->method('get')->with($customerEmail) + ->willReturn($customer); + $this->customer->expects($this->atLeastOnce())->method('getResetPasswordLinkExpirationPeriod') + ->willReturn(100000); + $this->string->expects($this->any())->method('strlen')->willReturnCallback( + function ($string) { + return strlen($string); + } + ); + $this->customerRegistry->expects($this->atLeastOnce())->method('retrieveSecureData') + ->willReturn($this->customerSecure); + + $this->customerSecure->expects($this->once()) + ->method('setRpToken') + ->with(null); + $this->customerSecure->expects($this->once()) + ->method('setRpTokenCreatedAt') + ->with(null); + $this->customerSecure->expects($this->any()) + ->method('setPasswordHash') + ->willReturn(null); + + $this->sessionManager->expects($this->atLeastOnce())->method('destroy'); + $this->sessionManager->expects($this->atLeastOnce())->method('start'); + $this->sessionManager->expects($this->atLeastOnce())->method('writeClose'); + $this->sessionManager->expects($this->atLeastOnce())->method('getSessionId'); + $visitor = $this->getMockBuilder(\Magento\Customer\Model\Visitor::class) + ->disableOriginalConstructor() + ->setMethods(['getSessionId']) + ->getMock(); + $visitor->expects($this->at(0))->method('getSessionId')->willReturn('session_id_1'); + $visitor->expects($this->at(1))->method('getSessionId')->willReturn('session_id_2'); + $visitorCollection = $this->getMockBuilder( + \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class + ) + ->disableOriginalConstructor()->setMethods(['addFieldToFilter', 'getItems'])->getMock(); + $visitorCollection->expects($this->atLeastOnce())->method('addFieldToFilter')->willReturnSelf(); + $visitorCollection->expects($this->atLeastOnce())->method('getItems')->willReturn([$visitor, $visitor]); + $this->visitorCollectionFactory->expects($this->atLeastOnce())->method('create') + ->willReturn($visitorCollection); + $this->saveHandler->expects($this->at(0))->method('destroy')->with('session_id_1'); + $this->saveHandler->expects($this->at(1))->method('destroy')->with('session_id_2'); + $this->assertTrue($this->accountManagement->resetPassword($customerEmail, $resetToken, $newPassword)); + } + /** * @return void */ diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Source/WebsiteTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Source/WebsiteTest.php index 1f8ce3baaa54c..aef77979acd02 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Source/WebsiteTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Source/WebsiteTest.php @@ -7,6 +7,8 @@ use Magento\Customer\Model\Customer\Attribute\Source\Website; use Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\ObjectManagerInterface; class WebsiteTest extends \PHPUnit_Framework_TestCase { @@ -22,20 +24,37 @@ class WebsiteTest extends \PHPUnit_Framework_TestCase /** @var \Magento\Store\Model\System\Store|\PHPUnit_Framework_MockObject_MockObject */ protected $storeMock; + /** @var ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject */ + private $objectManagerMock; + protected function setUp() { $this->collectionFactoryMock = - $this->getMockBuilder('Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory') + $this->getMockBuilder(\Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory::class) ->disableOriginalConstructor() ->getMock(); $this->optionFactoryMock = - $this->getMockBuilder('Magento\Eav\Model\ResourceModel\Entity\Attribute\OptionFactory') + $this->getMockBuilder(\Magento\Eav\Model\ResourceModel\Entity\Attribute\OptionFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->storeMock = $this->getMockBuilder(\Magento\Store\Model\System\Store::class) ->disableOriginalConstructor() ->getMock(); - $this->storeMock = $this->getMockBuilder('Magento\Store\Model\System\Store') + + $this->objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->setMethods(['get']) + ->getMockForAbstractClass(); + + $escaper = $this->getMockBuilder(\Magento\Framework\Escaper::class) ->disableOriginalConstructor() ->getMock(); + ObjectManager::setInstance($this->objectManagerMock); + $this->objectManagerMock->expects($this->any()) + ->method('get') + ->with(\Magento\Framework\Escaper::class) + ->willReturn($escaper); + $this->model = new Website( $this->collectionFactoryMock, $this->optionFactoryMock, @@ -91,4 +110,12 @@ public function testGetOptionTextWithoutOption() $this->assertEquals(false, $this->model->getOptionText('value')); } + + protected function tearDown() + { + $property = (new \ReflectionClass(ObjectManager::class))->getProperty('_instance'); + $property->setAccessible(true); + $property->setValue(null, null); + parent::tearDown(); + } } diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/Attribute/Source/CountryWithWebsitesTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/Attribute/Source/CountryWithWebsitesTest.php index 8d66bb406aee3..a682298378294 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/Attribute/Source/CountryWithWebsitesTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/Attribute/Source/CountryWithWebsitesTest.php @@ -12,7 +12,13 @@ use Magento\Framework\Data\Collection\AbstractDb; use Magento\Store\Api\Data\WebsiteInterface; use Magento\Store\Model\StoreManagerInterface; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\ObjectManagerInterface; +/** + * Tests for \Magento\Customer\Model\ResourceModel\Address\Attribute\Source\CountryWithWebsites + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class CountryWithWebsitesTest extends \PHPUnit_Framework_TestCase { /** @@ -40,6 +46,9 @@ class CountryWithWebsitesTest extends \PHPUnit_Framework_TestCase */ private $shareConfigMock; + /** @var ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject */ + private $objectManagerMock; + public function setUp() { $this->countriesFactoryMock = @@ -62,6 +71,21 @@ public function setUp() $this->shareConfigMock = $this->getMockBuilder(Share::class) ->disableOriginalConstructor() ->getMock(); + + $this->objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->setMethods(['get']) + ->getMockForAbstractClass(); + + $escaper = $this->getMockBuilder(\Magento\Framework\Escaper::class) + ->disableOriginalConstructor() + ->getMock(); + + ObjectManager::setInstance($this->objectManagerMock); + $this->objectManagerMock->expects($this->any()) + ->method('get') + ->with(\Magento\Framework\Escaper::class) + ->willReturn($escaper); + $this->countryByWebsite = new CountryWithWebsites( $eavCollectionFactoryMock, $optionsFactoryMock, @@ -117,4 +141,12 @@ public function testGetAllOptions() ['value' => 'AM', 'label' => 'UZ', 'website_ids' => [1, 2]] ], $this->countryByWebsite->getAllOptions()); } + + protected function tearDown() + { + $property = (new \ReflectionClass(ObjectManager::class))->getProperty('_instance'); + $property->setAccessible(true); + $property->setValue(null, null); + parent::tearDown(); + } } diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/AddressRepositoryTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/AddressRepositoryTest.php index 5a03b4b615f65..8df72f96f93c7 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/AddressRepositoryTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/AddressRepositoryTest.php @@ -5,6 +5,15 @@ */ namespace Magento\Customer\Test\Unit\Model\ResourceModel; +use Magento\Customer\Api\Data\AddressInterface as AddressData; +use Magento\Directory\Model\ResourceModel\Country\Collection as Countries; +use Magento\Framework\Exception\InputException; + +/** + * Unit test for Magento\Customer\Model\ResourceModel\AddressRepository + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class AddressRepositoryTest extends \PHPUnit_Framework_TestCase { /** @@ -64,34 +73,46 @@ class AddressRepositoryTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->addressFactory = $this->getMock('Magento\Customer\Model\AddressFactory', ['create'], [], '', false); - $this->addressRegistry = $this->getMock('Magento\Customer\Model\AddressRegistry', [], [], '', false); - $this->customerRegistry = $this->getMock('Magento\Customer\Model\CustomerRegistry', [], [], '', false); - $this->addressResourceModel = $this->getMock('Magento\Customer\Model\ResourceModel\Address', [], [], '', false); - $this->directoryData = $this->getMock('Magento\Directory\Helper\Data', [], [], '', false); + $this->addressFactory = $this->getMock( + \Magento\Customer\Model\AddressFactory::class, + ['create'], + [], + '', + false + ); + $this->addressRegistry = $this->getMock(\Magento\Customer\Model\AddressRegistry::class, [], [], '', false); + $this->customerRegistry = $this->getMock(\Magento\Customer\Model\CustomerRegistry::class, [], [], '', false); + $this->addressResourceModel = $this->getMock( + \Magento\Customer\Model\ResourceModel\Address::class, + [], + [], + '', + false + ); + $this->directoryData = $this->getMock(\Magento\Directory\Helper\Data::class, [], [], '', false); $this->addressSearchResultsFactory = $this->getMock( - 'Magento\Customer\Api\Data\AddressSearchResultsInterfaceFactory', + \Magento\Customer\Api\Data\AddressSearchResultsInterfaceFactory::class, ['create'], [], '', false ); $this->addressCollectionFactory = $this->getMock( - 'Magento\Customer\Model\ResourceModel\Address\CollectionFactory', + \Magento\Customer\Model\ResourceModel\Address\CollectionFactory::class, ['create'], [], '', false ); $this->extensionAttributesJoinProcessor = $this->getMockForAbstractClass( - 'Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface', + \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface::class, [], '', false ); - $this->customer = $this->getMock('Magento\Customer\Model\Customer', [], [], '', false); + $this->customer = $this->getMock(\Magento\Customer\Model\Customer::class, [], [], '', false); $this->address = $this->getMock( - 'Magento\Customer\Model\Address', + \Magento\Customer\Model\Address::class, [ 'getId', 'getCountryId', @@ -109,6 +130,7 @@ protected function setUp() 'save', 'getDataModel', 'getCustomerId', + 'getPostcode', ], [], '', @@ -131,9 +153,9 @@ public function testSave() { $customerId = 34; $addressId = 53; - $customerAddress = $this->getMockForAbstractClass('Magento\Customer\Api\Data\AddressInterface', [], '', false); + $customerAddress = $this->getMockForAbstractClass(AddressData::class, [], '', false); $addressCollection = - $this->getMock('Magento\Customer\Model\ResourceModel\Address\Collection', [], [], '', false); + $this->getMock(\Magento\Customer\Model\ResourceModel\Address\Collection::class, [], [], '', false); $customerAddress->expects($this->atLeastOnce()) ->method('getCustomerId') ->willReturn($customerId); @@ -189,7 +211,7 @@ public function testSaveWithException() { $customerId = 34; $addressId = 53; - $customerAddress = $this->getMockForAbstractClass('Magento\Customer\Api\Data\AddressInterface', [], '', false); + $customerAddress = $this->getMockForAbstractClass(AddressData::class, [], '', false); $customerAddress->expects($this->atLeastOnce()) ->method('getCustomerId') ->willReturn($customerId); @@ -220,7 +242,7 @@ public function testSaveWithInvalidRegion() { $customerId = 34; $addressId = 53; - $customerAddress = $this->getMockForAbstractClass('Magento\Customer\Api\Data\AddressInterface', [], '', false); + $customerAddress = $this->getMockForAbstractClass(AddressData::class, [], '', false); $customerAddress->expects($this->atLeastOnce()) ->method('getCustomerId') ->willReturn($customerId); @@ -238,9 +260,9 @@ public function testSaveWithInvalidRegion() $this->address->expects($this->once()) ->method('updateData') ->with($customerAddress); - $countryModel = $this->getMock('Magento\Directory\Model\Country', [], [], '', false); + $countryModel = $this->getMock(\Magento\Directory\Model\Country::class, [], [], '', false); $regionCollection = $this->getMock( - 'Magento\Directory\Model\ResourceModel\Region\Collection', + \Magento\Directory\Model\ResourceModel\Region\Collection::class, [], [], '', @@ -269,7 +291,7 @@ public function testSaveWithInvalidRegion() $this->address->expects($this->once()) ->method('getTelephone') ->willReturn('23423423423'); - $this->address->expects($this->never()) + $this->address->expects($this->once()) ->method('getRegionId') ->willReturn(null); @@ -282,7 +304,7 @@ public function testSaveWithInvalidRegion() $countryModel->expects($this->once()) ->method('getRegionCollection') ->willReturn($regionCollection); - $regionCollection->expects($this->once()) + $regionCollection->expects($this->never()) ->method('count') ->willReturn(0); $this->directoryData->expects($this->once()) @@ -293,6 +315,15 @@ public function testSaveWithInvalidRegion() ->method('getRegion') ->willReturn(''); + /** @var \PHPUnit_Framework_MockObject_MockObject $countryCollection */ + $countryCollection = $this->getMockBuilder(Countries::class) + ->disableOriginalConstructor() + ->getMock(); + $countryCollection->expects($this->once())->method('getAllIds')->willReturn(['1', '2']); + $this->directoryData->expects($this->once()) + ->method('getCountryCollection') + ->willReturn($countryCollection); + $this->repository->save($customerAddress); } @@ -304,7 +335,7 @@ public function testSaveWithInvalidRegionId() { $customerId = 34; $addressId = 53; - $customerAddress = $this->getMockForAbstractClass('Magento\Customer\Api\Data\AddressInterface', [], '', false); + $customerAddress = $this->getMockForAbstractClass(AddressData::class, [], '', false); $customerAddress->expects($this->atLeastOnce()) ->method('getCustomerId') ->willReturn($customerId); @@ -322,9 +353,9 @@ public function testSaveWithInvalidRegionId() $this->address->expects($this->once()) ->method('updateData') ->with($customerAddress); - $countryModel = $this->getMock('Magento\Directory\Model\Country', [], [], '', false); + $countryModel = $this->getMock(\Magento\Directory\Model\Country::class, [], [], '', false); $regionCollection = $this->getMock( - 'Magento\Directory\Model\ResourceModel\Region\Collection', + \Magento\Directory\Model\ResourceModel\Region\Collection::class, [], [], '', @@ -355,7 +386,7 @@ public function testSaveWithInvalidRegionId() ->willReturn('23423423423'); $this->address->expects($this->once()) ->method('getRegionId') - ->willReturn(2); + ->willReturn(''); $this->directoryData->expects($this->once()) ->method('getCountriesWithOptionalZip') @@ -366,28 +397,34 @@ public function testSaveWithInvalidRegionId() $countryModel->expects($this->once()) ->method('getRegionCollection') ->willReturn($regionCollection); - $regionCollection->expects($this->atLeastOnce()) - ->method('count') - ->willReturn(2); $regionCollection->expects($this->once()) - ->method('getData') + ->method('getAllIds') ->willReturn([5, 6, 7, 8, 9]); $this->directoryData->expects($this->once()) ->method('isRegionRequired') ->with(1) ->willReturn(true); - $this->address->expects($this->never()) + $this->address->expects($this->once()) ->method('getRegion') ->willReturn(''); + /** @var \PHPUnit_Framework_MockObject_MockObject $countryCollection */ + $countryCollection = $this->getMockBuilder(Countries::class) + ->disableOriginalConstructor() + ->getMock(); + $countryCollection->expects($this->once())->method('getAllIds')->willReturn(['1', '2']); + $this->directoryData->expects($this->once()) + ->method('getCountryCollection') + ->willReturn($countryCollection); + $this->repository->save($customerAddress); } protected function prepareMocksForInvalidAddressValidation() { - $countryModel = $this->getMock('Magento\Directory\Model\Country', [], [], '', false); + $countryModel = $this->getMock(\Magento\Directory\Model\Country::class, [], [], '', false); $regionCollection = $this->getMock( - 'Magento\Directory\Model\ResourceModel\Region\Collection', + \Magento\Directory\Model\ResourceModel\Region\Collection::class, [], [], '', @@ -417,16 +454,16 @@ protected function prepareMocksForInvalidAddressValidation() $this->directoryData->expects($this->once()) ->method('getCountriesWithOptionalZip') ->willReturn([]); - $this->address->expects($this->once()) + $this->address->expects($this->never()) ->method('getCountryModel') ->willReturn($countryModel); - $countryModel->expects($this->once()) + $countryModel->expects($this->never()) ->method('getRegionCollection') ->willReturn($regionCollection); - $regionCollection->expects($this->once()) + $regionCollection->expects($this->never()) ->method('count') ->willReturn(0); - $this->directoryData->expects($this->once()) + $this->directoryData->expects($this->never()) ->method('isRegionRequired') ->with(null) ->willReturn(true); @@ -434,7 +471,7 @@ protected function prepareMocksForInvalidAddressValidation() public function testGetById() { - $customerAddress = $this->getMockForAbstractClass('Magento\Customer\Api\Data\AddressInterface', [], '', false); + $customerAddress = $this->getMockForAbstractClass(AddressData::class, [], '', false); $this->addressRegistry->expects($this->once()) ->method('retrieve') ->with(12) @@ -448,99 +485,63 @@ public function testGetById() public function testGetList() { - $filterGroup = $this->getMock('Magento\Framework\Api\Search\FilterGroup', [], [], '', false); - $filter = $this->getMock('Magento\Framework\Api\Filter', [], [], '', false); - $collection = $this->getMock('Magento\Customer\Model\ResourceModel\Address\Collection', [], [], '', false); + $filterGroup = $this->getMock(\Magento\Framework\Api\Search\FilterGroup::class, [], [], '', false); + $filter = $this->getMock(\Magento\Framework\Api\Filter::class, [], [], '', false); + $collection = $this->getMock( + \Magento\Customer\Model\ResourceModel\Address\Collection::class, + [], + [], + '', + false + ); $searchResults = $this->getMockForAbstractClass( - 'Magento\Customer\Api\Data\AddressSearchResultsInterface', + \Magento\Customer\Api\Data\AddressSearchResultsInterface::class, [], '', false ); $searchCriteria = $this->getMockForAbstractClass( - 'Magento\Framework\Api\SearchCriteriaInterface', + \Magento\Framework\Api\SearchCriteriaInterface::class, [], '', false ); - $this->addressSearchResultsFactory->expects($this->once()) - ->method('create') - ->willReturn($searchResults); - $this->addressCollectionFactory->expects($this->once()) - ->method('create') - ->willReturn($collection); + $this->addressSearchResultsFactory->expects($this->once())->method('create')->willReturn($searchResults); + $this->addressCollectionFactory->expects($this->once())->method('create')->willReturn($collection); $this->extensionAttributesJoinProcessor->expects($this->once()) ->method('process') - ->with($collection, 'Magento\Customer\Api\Data\AddressInterface'); - $searchCriteria->expects($this->once()) - ->method('getFilterGroups') - ->willReturn([$filterGroup]); - $filterGroup->expects($this->once()) - ->method('getFilters') - ->willReturn([$filter]); - $filter->expects($this->once()) - ->method('getConditionType') - ->willReturn(false); - $filter->expects($this->once()) - ->method('getField') - ->willReturn('Field'); - $filter->expects($this->atLeastOnce()) - ->method('getValue') - ->willReturn('Value'); + ->with($collection, AddressData::class); + $searchCriteria->expects($this->once())->method('getFilterGroups')->willReturn([$filterGroup]); + $filterGroup->expects($this->once())->method('getFilters')->willReturn([$filter]); + $filter->expects($this->once())->method('getConditionType')->willReturn(false); + $filter->expects($this->once())->method('getField')->willReturn('Field'); + $filter->expects($this->atLeastOnce())->method('getValue')->willReturn('Value'); $collection->expects($this->once()) ->method('addFieldToFilter') ->with([['attribute' => 'Field', 'eq' => 'Value']], [['eq' => 'Value']]); - $collection->expects($this->once()) - ->method('getSize') - ->willReturn(23); - $searchResults->expects($this->once()) - ->method('setTotalCount') - ->with(23); - $sortOrder = $this->getMock('Magento\Framework\Api\SortOrder', [], [], '', false); - $searchCriteria->expects($this->once()) - ->method('getSortOrders') - ->willReturn([$sortOrder]); - $sortOrder->expects($this->once()) - ->method('getField') - ->willReturn('Field'); + $collection->expects($this->once())->method('getSize')->willReturn(23); + $searchResults->expects($this->once())->method('setTotalCount')->with(23); + $sortOrder = $this->getMock(\Magento\Framework\Api\SortOrder::class, [], [], '', false); + $searchCriteria->expects($this->once())->method('getSortOrders')->willReturn([$sortOrder]); + $sortOrder->expects($this->once())->method('getField')->willReturn('Field'); $sortOrder->expects($this->once()) ->method('getDirection') ->willReturn(\Magento\Framework\Api\SortOrder::SORT_ASC); - $collection->expects($this->once()) - ->method('addOrder') - ->with('Field', 'ASC'); - $searchCriteria->expects($this->once()) - ->method('getCurrentPage') - ->willReturn(1); - $collection->expects($this->once()) - ->method('setCurPage') - ->with(1); - $searchCriteria->expects($this->once()) - ->method('getPageSize') - ->willReturn(10); - $collection->expects($this->once()) - ->method('setPageSize') - ->with(10); - $collection->expects($this->once()) - ->method('getItems') - ->willReturn([$this->address]); - $this->address->expects($this->once()) - ->method('getId') - ->willReturn(12); - $customerAddress = $this->getMockForAbstractClass('Magento\Customer\Api\Data\AddressInterface', [], '', false); + $collection->expects($this->once())->method('addOrder')->with('Field', 'ASC'); + $searchCriteria->expects($this->once())->method('getCurrentPage')->willReturn(1); + $collection->expects($this->once())->method('setCurPage')->with(1); + $searchCriteria->expects($this->once())->method('getPageSize')->willReturn(10); + $collection->expects($this->once())->method('setPageSize')->with(10); + $collection->expects($this->once())->method('getItems')->willReturn([$this->address]); + $this->address->expects($this->once())->method('getId')->willReturn(12); + $customerAddress = $this->getMockForAbstractClass(AddressData::class, [], '', false); $this->addressRegistry->expects($this->once()) ->method('retrieve') ->with(12) ->willReturn($this->address); - $this->address->expects($this->once()) - ->method('getDataModel') - ->willReturn($customerAddress); - $searchResults->expects($this->once()) - ->method('setItems') - ->with([$customerAddress]); - $searchResults->expects($this->once()) - ->method('setSearchCriteria') - ->with($searchCriteria); + $this->address->expects($this->once())->method('getDataModel')->willReturn($customerAddress); + $searchResults->expects($this->once())->method('setItems')->with([$customerAddress]); + $searchResults->expects($this->once())->method('setSearchCriteria')->with($searchCriteria); $this->assertSame($searchResults, $this->repository->getList($searchCriteria)); } @@ -551,19 +552,20 @@ public function testDelete() $customerId = 43; $addressCollection = $this->getMock( - 'Magento\Customer\Model\ResourceModel\Address\Collection', + \Magento\Customer\Model\ResourceModel\Address\Collection::class, [], [], '', false ); - $customerAddress = $this->getMockForAbstractClass('Magento\Customer\Api\Data\AddressInterface', [], '', false); - $customerAddress->expects($this->once()) - ->method('getId') - ->willReturn($addressId); - $this->address->expects($this->once()) - ->method('getCustomerId') - ->willReturn($customerId); + $customerAddress = $this->getMockForAbstractClass( + \Magento\Customer\Api\Data\AddressInterface::class, + [], + '', + false + ); + $customerAddress->expects($this->once())->method('getId')->willReturn($addressId); + $this->address->expects($this->once())->method('getCustomerId')->willReturn($customerId); $this->addressRegistry->expects($this->once()) ->method('retrieve') @@ -574,17 +576,10 @@ public function testDelete() ->with($customerId) ->willReturn($this->customer); - $this->customer->expects($this->once()) - ->method('getAddressesCollection') - ->willReturn($addressCollection); - $addressCollection->expects($this->once()) - ->method('clear'); - $this->addressResourceModel->expects($this->once()) - ->method('delete') - ->with($this->address); - $this->addressRegistry->expects($this->once()) - ->method('remove') - ->with($addressId); + $this->customer->expects($this->once())->method('getAddressesCollection')->willReturn($addressCollection); + $addressCollection->expects($this->once())->method('clear'); + $this->addressResourceModel->expects($this->once())->method('delete')->with($this->address); + $this->addressRegistry->expects($this->once())->method('remove')->with($addressId); $this->assertTrue($this->repository->delete($customerAddress)); } @@ -598,7 +593,7 @@ public function testDeleteById() ->method('getCustomerId') ->willReturn($customerId); $addressCollection = $this->getMock( - 'Magento\Customer\Model\ResourceModel\Address\Collection', + \Magento\Customer\Model\ResourceModel\Address\Collection::class, [], [], '', @@ -626,4 +621,108 @@ public function testDeleteById() $this->assertTrue($this->repository->deleteById($addressId)); } + + public function testInvalidCountryId() + { + $customerAddress = $this->prepareAddressData('InvalidId', 0); + + try { + $this->repository->save($customerAddress); + $this->fail('Validation passed with invalid country ID'); + } catch (InputException $ex) { + $this->assertCount(0, $ex->getErrors()); + $this->assertEquals( + __( + 'Invalid value of "%value" provided for the %fieldName field.', + [ + 'fieldName' => 'countryId', + 'value' => 'InvalidId' + ] + ), + $ex->getMessage() + ); + } + } + + public function testInvalidRegionId() + { + $customerAddress = $this->prepareAddressData(1, 'InvalidId'); + + try { + $this->repository->save($customerAddress); + $this->fail('Validation passed with invalid country ID'); + } catch (InputException $ex) { + $this->assertCount(0, $ex->getErrors()); + $this->assertEquals( + __( + 'Invalid value of "%value" provided for the %fieldName field.', + [ + 'fieldName' => 'regionId', + 'value' => 'InvalidId' + ] + ), + $ex->getMessage() + ); + } + } + + /** + * Prepare address data. + * + * @param int|string $countryId + * @param int|string $regionId + * @return AddressData|\PHPUnit_Framework_MockObject_MockObject + */ + private function prepareAddressData($countryId, $regionId) + { + $customerId = 34; + $addressId = 22; + $customerAddress = $this->getMockForAbstractClass(AddressData::class, [], '', false); + $customerAddress->expects($this->atLeastOnce())->method('getCustomerId')->willReturn($customerId); + $customerAddress->expects($this->atLeastOnce())->method('getId')->willReturn($addressId); + $this->customerRegistry->expects($this->once()) + ->method('retrieve') + ->with($customerId) + ->willReturn($this->customer); + $this->addressRegistry->expects($this->once()) + ->method('retrieve') + ->with($addressId) + ->willReturn($this->address); + $this->address->expects($this->once())->method('updateData')->with($customerAddress); + $countryModel = $this->getMock(\Magento\Directory\Model\Country::class, [], [], '', false); + $regionCollection = $this->getMock( + \Magento\Directory\Model\ResourceModel\Region\Collection::class, + [], + [], + '', + false + ); + + $this->address->expects($this->once())->method('getShouldIgnoreValidation')->willReturn(false); + $this->address->expects($this->atLeastOnce())->method('getCountryId')->willReturn($countryId); + $this->address->expects($this->once())->method('getFirstname')->willReturn('First'); + $this->address->expects($this->once())->method('getLastname')->willReturn('Last'); + $this->address->expects($this->once())->method('getStreetLine')->with(1)->willReturn(['Some St.']); + $this->address->expects($this->once())->method('getCity')->willReturn('Kyiv'); + $this->address->expects($this->once())->method('getTelephone')->willReturn('4234236'); + $this->address->expects($this->any())->method('getRegionId')->willReturn($regionId); + $this->address->expects($this->any())->method('getPostcode')->willReturn('123456'); + + $this->directoryData->expects($this->once())->method('getCountriesWithOptionalZip')->willReturn([1]); + $this->directoryData->expects($this->any())->method('isRegionRequired')->willReturn(true); + $this->address->expects($this->any())->method('getCountryModel')->willReturn($countryModel); + $countryModel->expects($this->any())->method('getRegionCollection')->willReturn($regionCollection); + $regionCollection->expects($this->any())->method('getAllIds')->willReturn(['3', '4']); + + /** @var \PHPUnit_Framework_MockObject_MockObject $countryCollection */ + $countryCollection = $this->getMockBuilder(Countries::class) + ->disableOriginalConstructor() + ->getMock(); + $countryCollection->expects($this->once())->method('getAllIds')->willReturn(['1', '2']); + $this->directoryData->expects($this->once()) + ->method('getCountryCollection') + ->willReturn($countryCollection); + + return $customerAddress; + } } diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php index 556f8bdbd1f18..dce065b7b4295 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php @@ -160,7 +160,7 @@ protected function setUp() false ); $this->customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->setMethods(['__toArray']) + ->setMethods(['__toArray', 'setGroupId']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $this->model = new \Magento\Customer\Model\ResourceModel\CustomerRepository( @@ -187,6 +187,7 @@ public function testSave() { $customerId = 1; $storeId = 2; + $groupId = 1; $region = $this->getMockForAbstractClass(\Magento\Customer\Api\Data\RegionInterface::class, [], '', false); $address = $this->getMockForAbstractClass( @@ -222,6 +223,7 @@ public function testSave() [ 'getId', 'setId', + 'setGroupId', 'setStoreId', 'getStoreId', 'getAttributeSetId', @@ -254,7 +256,8 @@ public function testSave() 'getEmail', 'getWebsiteId', 'getAddresses', - 'setAddresses' + 'setAddresses', + 'getGroupId' ] ); $customerSecureData = $this->getMock( @@ -289,6 +292,17 @@ public function testSave() ->method('setCustomerId') ->with($customerId) ->willReturnSelf(); + + $this->customer->expects($this->exactly(2)) + ->method('getGroupId') + ->willReturn($groupId); + $customerAttributesMetaData->expects($this->once()) + ->method('getGroupId') + ->willReturn(null); + $customerModel->expects($this->once()) + ->method('setGroupId') + ->with($groupId); + $address->expects($this->once()) ->method('getRegion') ->willReturn($region); diff --git a/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php b/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php index 03c3902b0ec7e..babab76dd1eee 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php @@ -41,15 +41,15 @@ class VisitorTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->registry = $this->getMock('Magento\Framework\Registry'); - $this->session = $this->getMockBuilder('Magento\Customer\Model\Session') + $this->registry = $this->getMock(\Magento\Framework\Registry::class); + $this->session = $this->getMockBuilder(\Magento\Customer\Model\Session::class) ->disableOriginalConstructor() ->setMethods(['getSessionId', 'getVisitorData', 'setVisitorData']) ->getMock(); $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->resource = $this->getMockBuilder('Magento\Customer\Model\ResourceModel\Visitor') + $this->resource = $this->getMockBuilder(\Magento\Customer\Model\ResourceModel\Visitor::class) ->setMethods([ 'beginTransaction', '__sleep', @@ -64,7 +64,7 @@ protected function setUp() $this->resource->expects($this->any())->method('addCommitCallback')->will($this->returnSelf()); $arguments = $this->objectManagerHelper->getConstructArguments( - 'Magento\Customer\Model\Visitor', + \Magento\Customer\Model\Visitor::class, [ 'registry' => $this->registry, 'session' => $this->session, @@ -72,19 +72,19 @@ protected function setUp() ] ); - $this->visitor = $this->objectManagerHelper->getObject('Magento\Customer\Model\Visitor', $arguments); + $this->visitor = $this->objectManagerHelper->getObject(\Magento\Customer\Model\Visitor::class, $arguments); } public function testInitByRequest() { - $this->session->expects($this->once())->method('getSessionId') - ->will($this->returnValue('asdfhasdfjhkj2198sadf8sdf897')); + $oldSessionId = 'asdfhasdfjhkj2198sadf8sdf897'; + $newSessionId = 'bsdfhasdfjhkj2198sadf8sdf897'; + $this->session->expects($this->any())->method('getSessionId') + ->will($this->returnValue($newSessionId)); + $this->session->expects($this->atLeastOnce())->method('getVisitorData') + ->willReturn(['session_id' => $oldSessionId]); $this->visitor->initByRequest(null); - $this->assertEquals('asdfhasdfjhkj2198sadf8sdf897', $this->visitor->getSessionId()); - - $this->visitor->setData(['visitor_id' => 1]); - $this->visitor->initByRequest(null); - $this->assertNull($this->visitor->getSessionId()); + $this->assertEquals($newSessionId, $this->visitor->getSessionId()); } public function testSaveByRequest() @@ -96,7 +96,7 @@ public function testSaveByRequest() public function testIsModuleIgnored() { $this->visitor = $this->objectManagerHelper->getObject( - 'Magento\Customer\Model\Visitor', + \Magento\Customer\Model\Visitor::class, [ 'registry' => $this->registry, 'session' => $this->session, diff --git a/app/code/Magento/Customer/composer.json b/app/code/Magento/Customer/composer.json index 6b66fea8e56aa..53c8c633bcdbb 100644 --- a/app/code/Magento/Customer/composer.json +++ b/app/code/Magento/Customer/composer.json @@ -29,7 +29,7 @@ "magento/module-customer-sample-data": "Sample Data version:100.1.*" }, "type": "magento2-module", - "version": "100.1.10", + "version": "100.1.12", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Customer/etc/config.xml b/app/code/Magento/Customer/etc/config.xml index dbd7e16e19cea..729ab5d11a91b 100644 --- a/app/code/Magento/Customer/etc/config.xml +++ b/app/code/Magento/Customer/etc/config.xml @@ -81,17 +81,15 @@ T: {{var telephone}} {{depend vat_id}}
VAT: {{var vat_id}}{{/depend}}]]> F: {{var fax}}{{/depend}}| -{{depend vat_id}}
VAT: {{var vat_id}}{{/depend}}|]]>
+{{depend telephone}}T: {{var telephone}}|{{/depend}} +{{depend fax}}F: {{var fax}}|{{/depend}}| +{{depend vat_id}}VAT: {{var vat_id}}{{/depend}}|]]> diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml index d9b27940ad724..2435686c7c8a3 100644 --- a/app/code/Magento/Customer/etc/di.xml +++ b/app/code/Magento/Customer/etc/di.xml @@ -332,4 +332,9 @@ + + + Magento\Framework\Session\SessionManagerInterface\Proxy + + diff --git a/app/code/Magento/Customer/etc/events.xml b/app/code/Magento/Customer/etc/events.xml index 66c9a3813892c..d841d8faa9c38 100644 --- a/app/code/Magento/Customer/etc/events.xml +++ b/app/code/Magento/Customer/etc/events.xml @@ -10,7 +10,7 @@ - + diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_account.xml b/app/code/Magento/Customer/view/frontend/layout/customer_account.xml index 3f0a51b2c579e..dd972321f27e2 100644 --- a/app/code/Magento/Customer/view/frontend/layout/customer_account.xml +++ b/app/code/Magento/Customer/view/frontend/layout/customer_account.xml @@ -6,6 +6,9 @@ */ --> + + My Account + diff --git a/app/code/Magento/Customer/view/frontend/templates/account/dashboard/info.phtml b/app/code/Magento/Customer/view/frontend/templates/account/dashboard/info.phtml index 465e0fc0ee132..aa4bc3a5e939d 100644 --- a/app/code/Magento/Customer/view/frontend/templates/account/dashboard/info.phtml +++ b/app/code/Magento/Customer/view/frontend/templates/account/dashboard/info.phtml @@ -20,6 +20,7 @@ escapeHtml($block->getName()) ?>
escapeHtml($block->getCustomer()->getEmail()) ?>

+ getChildHtml('customer.account.dashboard.info.extra'); ?>
escapeHtml(__('Edit')) ?> diff --git a/app/code/Magento/Customer/view/frontend/web/js/action/login.js b/app/code/Magento/Customer/view/frontend/web/js/action/login.js index 3cf6d462d5e33..7d271f601e623 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/action/login.js +++ b/app/code/Magento/Customer/view/frontend/web/js/action/login.js @@ -8,9 +8,10 @@ define( 'jquery', 'mage/storage', 'Magento_Ui/js/model/messageList', - 'Magento_Customer/js/customer-data' + 'Magento_Customer/js/customer-data', + 'mage/translate' ], - function($, storage, globalMessageList, customerData) { + function($, storage, globalMessageList, customerData, $t) { 'use strict'; var callbacks = [], action = function(loginData, redirectUrl, isGlobal, messageContainer) { @@ -39,7 +40,9 @@ define( } } }).fail(function () { - messageContainer.addErrorMessage({'message': 'Could not authenticate. Please try again later'}); + messageContainer.addErrorMessage({ + 'message': $t('Could not authenticate. Please try again later') + }); callbacks.forEach(function(callback) { callback(loginData); }); diff --git a/app/code/Magento/CustomerImportExport/composer.json b/app/code/Magento/CustomerImportExport/composer.json index b19596bb92aee..d6da01b001618 100644 --- a/app/code/Magento/CustomerImportExport/composer.json +++ b/app/code/Magento/CustomerImportExport/composer.json @@ -12,7 +12,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.5", + "version": "100.1.6", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Deploy/composer.json b/app/code/Magento/Deploy/composer.json index 1455f39aaa94a..0e1fe6851b695 100644 --- a/app/code/Magento/Deploy/composer.json +++ b/app/code/Magento/Deploy/composer.json @@ -9,7 +9,7 @@ "magento/module-user": "100.1.*" }, "type": "magento2-module", - "version": "100.1.6", + "version": "100.1.7", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Developer/composer.json b/app/code/Magento/Developer/composer.json index 3f074b0f08667..2db8b7b844917 100644 --- a/app/code/Magento/Developer/composer.json +++ b/app/code/Magento/Developer/composer.json @@ -7,7 +7,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Dhl/composer.json b/app/code/Magento/Dhl/composer.json index c636c41f0c479..b1d801abd94ad 100644 --- a/app/code/Magento/Dhl/composer.json +++ b/app/code/Magento/Dhl/composer.json @@ -19,7 +19,7 @@ "magento/module-checkout": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Directory/Model/Country/Postcode/Config/Reader.php b/app/code/Magento/Directory/Model/Country/Postcode/Config/Reader.php index 6b654ba44127a..c968b5f1951d3 100644 --- a/app/code/Magento/Directory/Model/Country/Postcode/Config/Reader.php +++ b/app/code/Magento/Directory/Model/Country/Postcode/Config/Reader.php @@ -12,7 +12,10 @@ class Reader extends \Magento\Framework\Config\Reader\Filesystem * * @var array */ - protected $_idAttributes = ['/config/zip' => 'countryCode']; + protected $_idAttributes = [ + '/config/zip' => 'countryCode', + '/config/zip/codes/code' => 'id', + ]; /** * Construct the FileSystem Reader Class diff --git a/app/code/Magento/Directory/composer.json b/app/code/Magento/Directory/composer.json index 814bd48cc2e42..10c2b48d747dd 100644 --- a/app/code/Magento/Directory/composer.json +++ b/app/code/Magento/Directory/composer.json @@ -10,7 +10,7 @@ "lib-libxml": "*" }, "type": "magento2-module", - "version": "100.1.5", + "version": "100.1.6", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/Product/Edit/Link.php b/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/Product/Edit/Link.php index c685125ff2796..2da2195376b73 100644 --- a/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/Product/Edit/Link.php +++ b/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/Product/Edit/Link.php @@ -7,6 +7,7 @@ namespace Magento\Downloadable\Controller\Adminhtml\Downloadable\Product\Edit; use Magento\Downloadable\Helper\Download as DownloadHelper; +use Magento\Framework\App\Response\Http as HttpResponse; class Link extends \Magento\Catalog\Controller\Adminhtml\Product\Edit { @@ -15,7 +16,7 @@ class Link extends \Magento\Catalog\Controller\Adminhtml\Product\Edit */ protected function _createLink() { - return $this->_objectManager->create('Magento\Downloadable\Model\Link'); + return $this->_objectManager->create(\Magento\Downloadable\Model\Link::class); } /** @@ -23,7 +24,7 @@ protected function _createLink() */ protected function _getLink() { - return $this->_objectManager->get('Magento\Downloadable\Model\Link'); + return $this->_objectManager->get(\Magento\Downloadable\Model\Link::class); } /** @@ -36,13 +37,17 @@ protected function _getLink() protected function _processDownload($resource, $resourceType) { /* @var $helper \Magento\Downloadable\Helper\Download */ - $helper = $this->_objectManager->get('Magento\Downloadable\Helper\Download'); + $helper = $this->_objectManager->get(\Magento\Downloadable\Helper\Download::class); $helper->setResource($resource, $resourceType); $fileName = $helper->getFilename(); - $contentType = $helper->getContentType(); + //For security reasons we're making browsers to download the file + //instead of opening it. + $contentType = 'application/octet-stream'; - $this->getResponse()->setHttpResponseCode( + /** @var HttpResponse $response */ + $response = $this->getResponse(); + $response->setHttpResponseCode( 200 )->setHeader( 'Pragma', @@ -57,18 +62,16 @@ protected function _processDownload($resource, $resourceType) $contentType, true ); - if ($fileSize = $helper->getFileSize()) { - $this->getResponse()->setHeader('Content-Length', $fileSize); - } - - if ($contentDisposition = $helper->getContentDisposition()) { - $this->getResponse() - ->setHeader('Content-Disposition', $contentDisposition . '; filename=' . $fileName); + $response->setHeader('Content-Length', $fileSize); } - - $this->getResponse()->clearBody(); - $this->getResponse()->sendHeaders(); + $response->setHeader( + 'Content-Disposition', + 'attachment; filename=' . $fileName + ); + //Rendering + $response->clearBody(); + $response->sendHeaders(); $helper->output(); } @@ -92,7 +95,7 @@ public function execute() $resourceType = DownloadHelper::LINK_TYPE_URL; } elseif ($link->getLinkType() == DownloadHelper::LINK_TYPE_FILE) { $resource = $this->_objectManager->get( - 'Magento\Downloadable\Helper\File' + \Magento\Downloadable\Helper\File::class )->getFilePath( $this->_getLink()->getBasePath(), $link->getLinkFile() @@ -105,7 +108,7 @@ public function execute() $resourceType = DownloadHelper::LINK_TYPE_URL; } elseif ($link->getSampleType() == DownloadHelper::LINK_TYPE_FILE) { $resource = $this->_objectManager->get( - 'Magento\Downloadable\Helper\File' + \Magento\Downloadable\Helper\File::class )->getFilePath( $this->_getLink()->getBaseSamplePath(), $link->getSampleFile() diff --git a/app/code/Magento/Downloadable/Controller/Download.php b/app/code/Magento/Downloadable/Controller/Download.php index 10aecb9473039..f0bef425d4b45 100644 --- a/app/code/Magento/Downloadable/Controller/Download.php +++ b/app/code/Magento/Downloadable/Controller/Download.php @@ -6,6 +6,7 @@ namespace Magento\Downloadable\Controller; use Magento\Downloadable\Helper\Download as DownloadHelper; +use Magento\Framework\App\Response\Http as HttpResponse; /** * Download controller @@ -14,6 +15,13 @@ */ abstract class Download extends \Magento\Framework\App\Action\Action { + /** + * @var array + */ + private $disallowedContentTypes = [ + 'text/html', + ]; + /** * Prepare response to output resource contents * @@ -24,13 +32,16 @@ abstract class Download extends \Magento\Framework\App\Action\Action protected function _processDownload($path, $resourceType) { /* @var $helper DownloadHelper */ - $helper = $this->_objectManager->get('Magento\Downloadable\Helper\Download'); + $helper = $this->_objectManager->get(\Magento\Downloadable\Helper\Download::class); $helper->setResource($path, $resourceType); $fileName = $helper->getFilename(); + $contentType = $helper->getContentType(); - $this->getResponse()->setHttpResponseCode( + /** @var HttpResponse $response */ + $response = $this->getResponse(); + $response->setHttpResponseCode( 200 )->setHeader( 'Pragma', @@ -47,15 +58,19 @@ protected function _processDownload($path, $resourceType) ); if ($fileSize = $helper->getFileSize()) { - $this->getResponse()->setHeader('Content-Length', $fileSize); + $response->setHeader('Content-Length', $fileSize); } - if ($contentDisposition = $helper->getContentDisposition()) { - $this->getResponse()->setHeader('Content-Disposition', $contentDisposition . '; filename=' . $fileName); + $contentDisposition = $helper->getContentDisposition(); + if (!$contentDisposition || in_array($contentType, $this->disallowedContentTypes)) { + // For security reasons we force browsers to download the file instead of opening it. + $contentDisposition = \Zend_Mime::DISPOSITION_ATTACHMENT; } - $this->getResponse()->clearBody(); - $this->getResponse()->sendHeaders(); + $response->setHeader('Content-Disposition', $contentDisposition . '; filename=' . $fileName); + //Rendering + $response->clearBody(); + $response->sendHeaders(); $helper->output(); } @@ -67,6 +82,6 @@ protected function _processDownload($path, $resourceType) */ protected function _getLink() { - return $this->_objectManager->get('Magento\Downloadable\Model\Link'); + return $this->_objectManager->get(\Magento\Downloadable\Model\Link::class); } } diff --git a/app/code/Magento/Downloadable/Test/Unit/Controller/Adminhtml/Downloadable/Product/Edit/LinkTest.php b/app/code/Magento/Downloadable/Test/Unit/Controller/Adminhtml/Downloadable/Product/Edit/LinkTest.php index cb9f17557b755..218d9156a2f72 100644 --- a/app/code/Magento/Downloadable/Test/Unit/Controller/Adminhtml/Downloadable/Product/Edit/LinkTest.php +++ b/app/code/Magento/Downloadable/Test/Unit/Controller/Adminhtml/Downloadable/Product/Edit/LinkTest.php @@ -22,7 +22,7 @@ class LinkTest extends \PHPUnit_Framework_TestCase protected $request; /** - * @var \Magento\Framework\App\ResponseInterface + * @var \Magento\Framework\App\ResponseInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $response; @@ -50,10 +50,10 @@ protected function setUp() { $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->request = $this->getMockBuilder('Magento\Framework\App\Request\Http') + $this->request = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) ->disableOriginalConstructor()->getMock(); $this->response = $this->getMock( - '\Magento\Framework\App\ResponseInterface', + \Magento\Framework\App\ResponseInterface::class, [ 'setHttpResponseCode', 'clearBody', @@ -63,7 +63,7 @@ protected function setUp() ] ); $this->fileHelper = $this->getMock( - '\Magento\Downloadable\Helper\File', + \Magento\Downloadable\Helper\File::class, [ 'getFilePath' ], @@ -72,7 +72,7 @@ protected function setUp() false ); $this->downloadHelper = $this->getMock( - 'Magento\Downloadable\Helper\Download', + \Magento\Downloadable\Helper\Download::class, [ 'setResource', 'getFilename', @@ -86,7 +86,7 @@ protected function setUp() false ); $this->linkModel = $this->getMock( - '\Magento\Downloadable\Controller\Adminhtml\Downloadable\Product\Edit\Link', + \Magento\Downloadable\Controller\Adminhtml\Downloadable\Product\Edit\Link::class, [ 'load', 'getId', @@ -104,7 +104,7 @@ protected function setUp() false ); $this->objectManager = $this->getMock( - '\Magento\Framework\ObjectManager\ObjectManager', + \Magento\Framework\ObjectManager\ObjectManager::class, [ 'create', 'get' @@ -115,7 +115,7 @@ protected function setUp() ); $this->link = $this->objectManagerHelper->getObject( - 'Magento\Downloadable\Controller\Adminhtml\Downloadable\Product\Edit\Link', + \Magento\Downloadable\Controller\Adminhtml\Downloadable\Product\Edit\Link::class, [ 'objectManager' => $this->objectManager, 'request' => $this->request, @@ -130,6 +130,8 @@ protected function setUp() */ public function testExecuteFile($fileType) { + $fileSize = 58493; + $fileName = 'link.jpg'; $this->request->expects($this->at(0))->method('getParam')->with('id', 0) ->will($this->returnValue(1)); $this->request->expects($this->at(1))->method('getParam')->with('type', 0) @@ -138,34 +140,47 @@ public function testExecuteFile($fileType) ->will($this->returnSelf()); $this->response->expects($this->once())->method('clearBody') ->will($this->returnSelf()); - $this->response->expects($this->any())->method('setHeader') - ->will($this->returnSelf()); + $this->response + ->expects($this->any()) + ->method('setHeader') + ->withConsecutive( + ['Pragma', 'public', true], + [ + 'Cache-Control', + 'must-revalidate, post-check=0, pre-check=0', + true, + ], + ['Content-type', 'application/octet-stream'], + ['Content-Length', $fileSize], + ['Content-Disposition', 'attachment; filename=' . $fileName] + ) + ->willReturnSelf(); $this->response->expects($this->once())->method('sendHeaders') ->will($this->returnSelf()); - $this->objectManager->expects($this->at(1))->method('get')->with('Magento\Downloadable\Helper\File') + $this->objectManager->expects($this->at(1))->method('get')->with(\Magento\Downloadable\Helper\File::class) ->will($this->returnValue($this->fileHelper)); - $this->objectManager->expects($this->at(2))->method('get')->with('Magento\Downloadable\Model\Link') + $this->objectManager->expects($this->at(2))->method('get')->with(\Magento\Downloadable\Model\Link::class) ->will($this->returnValue($this->linkModel)); - $this->objectManager->expects($this->at(3))->method('get')->with('Magento\Downloadable\Helper\Download') + $this->objectManager->expects($this->at(3))->method('get')->with(\Magento\Downloadable\Helper\Download::class) ->will($this->returnValue($this->downloadHelper)); $this->fileHelper->expects($this->once())->method('getFilePath') ->will($this->returnValue('filepath/' . $fileType . '.jpg')); $this->downloadHelper->expects($this->once())->method('setResource') ->will($this->returnSelf()); $this->downloadHelper->expects($this->once())->method('getFilename') - ->will($this->returnValue('link.jpg')); - $this->downloadHelper->expects($this->once())->method('getContentType') + ->will($this->returnValue($fileName)); + $this->downloadHelper->expects($this->never())->method('getContentType') ->will($this->returnSelf('file')); $this->downloadHelper->expects($this->once())->method('getFileSize') - ->will($this->returnValue(null)); - $this->downloadHelper->expects($this->once())->method('getContentDisposition') + ->will($this->returnValue($fileSize)); + $this->downloadHelper->expects($this->never())->method('getContentDisposition') ->will($this->returnValue(null)); $this->downloadHelper->expects($this->once())->method('output') ->will($this->returnSelf()); $this->linkModel->expects($this->once())->method('load') ->will($this->returnSelf()); $this->linkModel->expects($this->once())->method('getId') - ->will($this->returnValue('1')); + ->will($this->returnValue('1')); $this->linkModel->expects($this->any())->method('get' . $fileType . 'Type') ->will($this->returnValue('file')); $this->objectManager->expects($this->once())->method('create') @@ -192,17 +207,17 @@ public function testExecuteUrl($fileType) ->will($this->returnSelf()); $this->response->expects($this->once())->method('sendHeaders') ->will($this->returnSelf()); - $this->objectManager->expects($this->at(1))->method('get')->with('Magento\Downloadable\Helper\Download') + $this->objectManager->expects($this->at(1))->method('get')->with(\Magento\Downloadable\Helper\Download::class) ->will($this->returnValue($this->downloadHelper)); $this->downloadHelper->expects($this->once())->method('setResource') ->will($this->returnSelf()); $this->downloadHelper->expects($this->once())->method('getFilename') ->will($this->returnValue('link.jpg')); - $this->downloadHelper->expects($this->once())->method('getContentType') + $this->downloadHelper->expects($this->never())->method('getContentType') ->will($this->returnSelf('url')); $this->downloadHelper->expects($this->once())->method('getFileSize') ->will($this->returnValue(null)); - $this->downloadHelper->expects($this->once())->method('getContentDisposition') + $this->downloadHelper->expects($this->never())->method('getContentDisposition') ->will($this->returnValue(null)); $this->downloadHelper->expects($this->once())->method('output') ->will($this->returnSelf()); diff --git a/app/code/Magento/Downloadable/Test/Unit/Controller/Adminhtml/Downloadable/Product/Edit/SampleTest.php b/app/code/Magento/Downloadable/Test/Unit/Controller/Adminhtml/Downloadable/Product/Edit/SampleTest.php index c5214305f9194..8718f94a3b6a5 100644 --- a/app/code/Magento/Downloadable/Test/Unit/Controller/Adminhtml/Downloadable/Product/Edit/SampleTest.php +++ b/app/code/Magento/Downloadable/Test/Unit/Controller/Adminhtml/Downloadable/Product/Edit/SampleTest.php @@ -50,10 +50,10 @@ protected function setUp() { $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->request = $this->getMockBuilder('Magento\Framework\App\Request\Http') + $this->request = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) ->disableOriginalConstructor()->getMock(); $this->response = $this->getMock( - '\Magento\Framework\App\ResponseInterface', + \Magento\Framework\App\ResponseInterface::class, [ 'setHttpResponseCode', 'clearBody', @@ -63,7 +63,7 @@ protected function setUp() ] ); $this->fileHelper = $this->getMock( - '\Magento\Downloadable\Helper\File', + \Magento\Downloadable\Helper\File::class, [ 'getFilePath' ], @@ -72,7 +72,7 @@ protected function setUp() false ); $this->downloadHelper = $this->getMock( - 'Magento\Downloadable\Helper\Download', + \Magento\Downloadable\Helper\Download::class, [ 'setResource', 'getFilename', @@ -86,7 +86,7 @@ protected function setUp() false ); $this->sampleModel = $this->getMock( - '\Magento\Downloadable\Controller\Adminhtml\Downloadable\Product\Edit\Sample', + \Magento\Downloadable\Controller\Adminhtml\Downloadable\Product\Edit\Sample::class, [ 'load', 'getId', @@ -101,7 +101,7 @@ protected function setUp() false ); $this->objectManager = $this->getMock( - '\Magento\Framework\ObjectManager\ObjectManager', + \Magento\Framework\ObjectManager\ObjectManager::class, [ 'create', 'get' @@ -111,7 +111,7 @@ protected function setUp() false ); $this->sample = $this->objectManagerHelper->getObject( - 'Magento\Downloadable\Controller\Adminhtml\Downloadable\Product\Edit\Sample', + \Magento\Downloadable\Controller\Adminhtml\Downloadable\Product\Edit\Sample::class, [ 'objectManager' => $this->objectManager, 'request' => $this->request, @@ -135,11 +135,11 @@ public function testExecuteFile() ->will($this->returnSelf()); $this->response->expects($this->once())->method('sendHeaders') ->will($this->returnSelf()); - $this->objectManager->expects($this->at(1))->method('get')->with('Magento\Downloadable\Helper\File') + $this->objectManager->expects($this->at(1))->method('get')->with(\Magento\Downloadable\Helper\File::class) ->will($this->returnValue($this->fileHelper)); - $this->objectManager->expects($this->at(2))->method('get')->with('Magento\Downloadable\Model\Sample') + $this->objectManager->expects($this->at(2))->method('get')->with(\Magento\Downloadable\Model\Sample::class) ->will($this->returnValue($this->sampleModel)); - $this->objectManager->expects($this->at(3))->method('get')->with('Magento\Downloadable\Helper\Download') + $this->objectManager->expects($this->at(3))->method('get')->with(\Magento\Downloadable\Helper\Download::class) ->will($this->returnValue($this->downloadHelper)); $this->fileHelper->expects($this->once())->method('getFilePath') ->will($this->returnValue('filepath/sample.jpg')); @@ -147,11 +147,11 @@ public function testExecuteFile() ->will($this->returnSelf()); $this->downloadHelper->expects($this->once())->method('getFilename') ->will($this->returnValue('sample.jpg')); - $this->downloadHelper->expects($this->once())->method('getContentType') + $this->downloadHelper->expects($this->never())->method('getContentType') ->will($this->returnSelf('file')); $this->downloadHelper->expects($this->once())->method('getFileSize') ->will($this->returnValue(null)); - $this->downloadHelper->expects($this->once())->method('getContentDisposition') + $this->downloadHelper->expects($this->never())->method('getContentDisposition') ->will($this->returnValue(null)); $this->downloadHelper->expects($this->once())->method('output') ->will($this->returnSelf()); @@ -182,17 +182,17 @@ public function testExecuteUrl() ->will($this->returnSelf()); $this->response->expects($this->once())->method('sendHeaders') ->will($this->returnSelf()); - $this->objectManager->expects($this->at(1))->method('get')->with('Magento\Downloadable\Helper\Download') + $this->objectManager->expects($this->at(1))->method('get')->with(\Magento\Downloadable\Helper\Download::class) ->will($this->returnValue($this->downloadHelper)); $this->downloadHelper->expects($this->once())->method('setResource') ->will($this->returnSelf()); $this->downloadHelper->expects($this->once())->method('getFilename') ->will($this->returnValue('sample.jpg')); - $this->downloadHelper->expects($this->once())->method('getContentType') + $this->downloadHelper->expects($this->never())->method('getContentType') ->will($this->returnSelf('url')); $this->downloadHelper->expects($this->once())->method('getFileSize') ->will($this->returnValue(null)); - $this->downloadHelper->expects($this->once())->method('getContentDisposition') + $this->downloadHelper->expects($this->never())->method('getContentDisposition') ->will($this->returnValue(null)); $this->downloadHelper->expects($this->once())->method('output') ->will($this->returnSelf()); diff --git a/app/code/Magento/Downloadable/Test/Unit/Controller/Download/LinkTest.php b/app/code/Magento/Downloadable/Test/Unit/Controller/Download/LinkTest.php index b7cd7eac5e8ce..b39d94036e23a 100644 --- a/app/code/Magento/Downloadable/Test/Unit/Controller/Download/LinkTest.php +++ b/app/code/Magento/Downloadable/Test/Unit/Controller/Download/LinkTest.php @@ -7,6 +7,11 @@ use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +/** + * Class LinkTest + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class LinkTest extends \PHPUnit_Framework_TestCase { /** @var \Magento\Downloadable\Controller\Download\Link */ @@ -82,10 +87,10 @@ protected function setUp() { $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->request = $this->getMockBuilder('Magento\Framework\App\Request\Http') + $this->request = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) ->disableOriginalConstructor()->getMock(); $this->response = $this->getMock( - '\Magento\Framework\App\ResponseInterface', + \Magento\Framework\App\ResponseInterface::class, [ 'setHttpResponseCode', 'clearBody', @@ -95,7 +100,7 @@ protected function setUp() ] ); $this->session = $this->getMock( - 'Magento\Customer\Model\Session', + \Magento\Customer\Model\Session::class, [ 'getCustomerId', 'authenticate', @@ -106,7 +111,7 @@ protected function setUp() false ); $this->helperData = $this->getMock( - 'Magento\Downloadable\Helper\Data', + \Magento\Downloadable\Helper\Data::class, [ 'getIsShareable' ], @@ -115,7 +120,7 @@ protected function setUp() false ); $this->downloadHelper = $this->getMock( - 'Magento\Downloadable\Helper\Download', + \Magento\Downloadable\Helper\Download::class, [ 'setResource', 'getFilename', @@ -129,7 +134,7 @@ protected function setUp() false ); $this->product = $this->getMock( - 'Magento\Catalog\Model\Product', + \Magento\Catalog\Model\Product::class, [ '_wakeup', 'load', @@ -142,7 +147,7 @@ protected function setUp() false ); $this->linkPurchasedItem = $this->getMock( - 'Magento\Downloadable\Model\Link\Purchased\Item', + \Magento\Downloadable\Model\Link\Purchased\Item::class, [ 'load', 'getId', @@ -163,7 +168,7 @@ protected function setUp() false ); $this->linkPurchased = $this->getMock( - 'Magento\Downloadable\Model\Link\Purchased', + \Magento\Downloadable\Model\Link\Purchased::class, [ 'load', 'getCustomerId' @@ -173,28 +178,28 @@ protected function setUp() false ); $this->messageManager = $this->getMock( - 'Magento\Framework\Message\ManagerInterface', + \Magento\Framework\Message\ManagerInterface::class, [], [], '', false ); $this->redirect = $this->getMock( - 'Magento\Framework\App\Response\RedirectInterface', + \Magento\Framework\App\Response\RedirectInterface::class, [], [], '', false ); $this->urlInterface = $this->getMock( - 'Magento\Framework\UrlInterface', + \Magento\Framework\UrlInterface::class, [], [], '', false ); $this->objectManager = $this->getMock( - '\Magento\Framework\ObjectManager\ObjectManager', + \Magento\Framework\ObjectManager\ObjectManager::class, [ 'create', 'get' @@ -204,7 +209,7 @@ protected function setUp() false ); $this->link = $this->objectManagerHelper->getObject( - 'Magento\Downloadable\Controller\Download\Link', + \Magento\Downloadable\Controller\Download\Link::class, [ 'objectManager' => $this->objectManager, 'request' => $this->request, @@ -219,12 +224,12 @@ public function testAbsentLinkId() { $this->objectManager->expects($this->once()) ->method('get') - ->with('Magento\Customer\Model\Session') + ->with(\Magento\Customer\Model\Session::class) ->willReturn($this->session); $this->request->expects($this->once())->method('getParam')->with('id', 0)->willReturn('some_id'); $this->objectManager->expects($this->once()) ->method('create') - ->with('Magento\Downloadable\Model\Link\Purchased\Item') + ->with(\Magento\Downloadable\Model\Link\Purchased\Item::class) ->willReturn($this->linkPurchasedItem); $this->linkPurchasedItem->expects($this->once()) ->method('load') @@ -243,12 +248,12 @@ public function testGetLinkForGuestCustomer() { $this->objectManager->expects($this->at(0)) ->method('get') - ->with('Magento\Customer\Model\Session') + ->with(\Magento\Customer\Model\Session::class) ->willReturn($this->session); $this->request->expects($this->once())->method('getParam')->with('id', 0)->willReturn('some_id'); $this->objectManager->expects($this->at(1)) ->method('create') - ->with('Magento\Downloadable\Model\Link\Purchased\Item') + ->with(\Magento\Downloadable\Model\Link\Purchased\Item::class) ->willReturn($this->linkPurchasedItem); $this->linkPurchasedItem->expects($this->once()) ->method('load') @@ -257,7 +262,7 @@ public function testGetLinkForGuestCustomer() $this->linkPurchasedItem->expects($this->once())->method('getId')->willReturn(5); $this->objectManager->expects($this->at(2)) ->method('get') - ->with('Magento\Downloadable\Helper\Data') + ->with(\Magento\Downloadable\Helper\Data::class) ->willReturn($this->helperData); $this->helperData->expects($this->once()) ->method('getIsShareable') @@ -266,7 +271,7 @@ public function testGetLinkForGuestCustomer() $this->session->expects($this->once())->method('getCustomerId')->willReturn(null); $this->objectManager->expects($this->at(3)) ->method('create') - ->with('Magento\Catalog\Model\Product') + ->with(\Magento\Catalog\Model\Product::class) ->willReturn($this->product); $this->linkPurchasedItem->expects($this->once())->method('getProductId')->willReturn('product_id'); $this->product->expects($this->once())->method('load')->with('product_id')->willReturnSelf(); @@ -279,7 +284,7 @@ public function testGetLinkForGuestCustomer() $this->session->expects($this->once())->method('authenticate')->willReturn(true); $this->objectManager->expects($this->at(4)) ->method('create') - ->with('Magento\Framework\UrlInterface') + ->with(\Magento\Framework\UrlInterface::class) ->willReturn($this->urlInterface); $this->urlInterface->expects($this->once()) ->method('getUrl') @@ -294,12 +299,12 @@ public function testGetLinkForWrongCustomer() { $this->objectManager->expects($this->at(0)) ->method('get') - ->with('Magento\Customer\Model\Session') + ->with(\Magento\Customer\Model\Session::class) ->willReturn($this->session); $this->request->expects($this->once())->method('getParam')->with('id', 0)->willReturn('some_id'); $this->objectManager->expects($this->at(1)) ->method('create') - ->with('Magento\Downloadable\Model\Link\Purchased\Item') + ->with(\Magento\Downloadable\Model\Link\Purchased\Item::class) ->willReturn($this->linkPurchasedItem); $this->linkPurchasedItem->expects($this->once()) ->method('load') @@ -308,7 +313,7 @@ public function testGetLinkForWrongCustomer() $this->linkPurchasedItem->expects($this->once())->method('getId')->willReturn(5); $this->objectManager->expects($this->at(2)) ->method('get') - ->with('Magento\Downloadable\Helper\Data') + ->with(\Magento\Downloadable\Helper\Data::class) ->willReturn($this->helperData); $this->helperData->expects($this->once()) ->method('getIsShareable') @@ -317,7 +322,7 @@ public function testGetLinkForWrongCustomer() $this->session->expects($this->once())->method('getCustomerId')->willReturn('customer_id'); $this->objectManager->expects($this->at(3)) ->method('create') - ->with('Magento\Downloadable\Model\Link\Purchased') + ->with(\Magento\Downloadable\Model\Link\Purchased::class) ->willReturn($this->linkPurchased); $this->linkPurchasedItem->expects($this->once())->method('getPurchasedId')->willReturn('purchased_id'); $this->linkPurchased->expects($this->once())->method('load')->with('purchased_id')->willReturnSelf(); @@ -330,16 +335,22 @@ public function testGetLinkForWrongCustomer() $this->assertEquals($this->response, $this->link->execute()); } - public function testExceptionInUpdateLinkStatus() + /** + * @param string $mimeType + * @param string $disposition + * @dataProvider downloadTypesDataProvider + * @return void + */ + public function testExceptionInUpdateLinkStatus($mimeType, $disposition) { $this->objectManager->expects($this->at(0)) ->method('get') - ->with('Magento\Customer\Model\Session') + ->with(\Magento\Customer\Model\Session::class) ->willReturn($this->session); $this->request->expects($this->once())->method('getParam')->with('id', 0)->willReturn('some_id'); $this->objectManager->expects($this->at(1)) ->method('create') - ->with('Magento\Downloadable\Model\Link\Purchased\Item') + ->with(\Magento\Downloadable\Model\Link\Purchased\Item::class) ->willReturn($this->linkPurchasedItem); $this->linkPurchasedItem->expects($this->once()) ->method('load') @@ -348,7 +359,7 @@ public function testExceptionInUpdateLinkStatus() $this->linkPurchasedItem->expects($this->once())->method('getId')->willReturn(5); $this->objectManager->expects($this->at(2)) ->method('get') - ->with('Magento\Downloadable\Helper\Data') + ->with(\Magento\Downloadable\Helper\Data::class) ->willReturn($this->helperData); $this->helperData->expects($this->once()) ->method('getIsShareable') @@ -360,7 +371,7 @@ public function testExceptionInUpdateLinkStatus() $this->linkPurchasedItem->expects($this->once())->method('getLinkType')->willReturn('url'); $this->linkPurchasedItem->expects($this->once())->method('getLinkUrl')->willReturn('link_url'); - $this->processDownload('link_url', 'url'); + $this->processDownload('link_url', 'url', $mimeType, $disposition); $this->linkPurchasedItem->expects($this->any())->method('setNumberOfDownloadsUsed')->willReturnSelf(); $this->linkPurchasedItem->expects($this->any())->method('setStatus')->with('expired')->willReturnSelf(); @@ -374,40 +385,43 @@ public function testExceptionInUpdateLinkStatus() $this->assertEquals($this->response, $this->link->execute()); } - private function processDownload($resource, $resourceType) + /** + * @param string $resource + * @param string $resourceType + * @param string $mimeType + * @param atring $disposition + * @return void + */ + private function processDownload($resource, $resourceType, $mimeType, $disposition) { + $fileSize = 58493; + $fileName = 'link.jpg'; + $this->objectManager->expects($this->at(3)) ->method('get') - ->with('Magento\Downloadable\Helper\Download') + ->with(\Magento\Downloadable\Helper\Download::class) ->willReturn($this->downloadHelper); $this->downloadHelper->expects($this->once()) ->method('setResource') ->with($resource, $resourceType) ->willReturnSelf(); - $this->downloadHelper->expects($this->once())->method('getFilename')->willReturn('file_name'); - $this->downloadHelper->expects($this->once())->method('getContentType')->willReturn('content_type'); + $this->downloadHelper->expects($this->once())->method('getFilename')->willReturn($fileName); + $this->downloadHelper->expects($this->once())->method('getContentType')->willReturn($mimeType); $this->response->expects($this->once())->method('setHttpResponseCode')->with(200)->willReturnSelf(); - $this->response->expects($this->at(1))->method('setHeader')->with('Pragma', 'public', true)->willReturnSelf(); - $this->response->expects($this->at(2)) - ->method('setHeader') - ->with('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true) - ->willReturnSelf(); - $this->response->expects($this->at(3)) + $this->response + ->expects($this->any()) ->method('setHeader') - ->with('Content-type', 'content_type', true) - ->willReturnSelf(); - $this->downloadHelper->expects($this->once())->method('getFileSize')->willReturn('file_size'); - $this->response->expects($this->at(4)) - ->method('setHeader') - ->with('Content-Length', 'file_size') - ->willReturnSelf(); - $this->downloadHelper->expects($this->once()) - ->method('getContentDisposition') - ->willReturn('content_disposition'); - $this->response->expects($this->at(5)) - ->method('setHeader') - ->with('Content-Disposition', 'content_disposition; filename=file_name') + ->withConsecutive( + ['Pragma', 'public', true], + ['Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true], + ['Content-type', $mimeType, true], + ['Content-Length', $fileSize], + ['Content-Disposition', $disposition . '; filename=' . $fileName] + ) ->willReturnSelf(); + + $this->downloadHelper->expects($this->once())->method('getContentDisposition')->willReturn($disposition); + $this->downloadHelper->expects($this->once())->method('getFileSize')->willReturn($fileSize); $this->response->expects($this->once())->method('clearBody')->willReturnSelf(); $this->response->expects($this->once())->method('sendHeaders')->willReturnSelf(); $this->downloadHelper->expects($this->once())->method('output'); @@ -423,12 +437,12 @@ public function testLinkNotAvailable($messageType, $status, $notice) { $this->objectManager->expects($this->at(0)) ->method('get') - ->with('Magento\Customer\Model\Session') + ->with(\Magento\Customer\Model\Session::class) ->willReturn($this->session); $this->request->expects($this->once())->method('getParam')->with('id', 0)->willReturn('some_id'); $this->objectManager->expects($this->at(1)) ->method('create') - ->with('Magento\Downloadable\Model\Link\Purchased\Item') + ->with(\Magento\Downloadable\Model\Link\Purchased\Item::class) ->willReturn($this->linkPurchasedItem); $this->linkPurchasedItem->expects($this->once()) ->method('load') @@ -437,7 +451,7 @@ public function testLinkNotAvailable($messageType, $status, $notice) $this->linkPurchasedItem->expects($this->once())->method('getId')->willReturn(5); $this->objectManager->expects($this->at(2)) ->method('get') - ->with('Magento\Downloadable\Helper\Data') + ->with(\Magento\Downloadable\Helper\Data::class) ->willReturn($this->helperData); $this->helperData->expects($this->once()) ->method('getIsShareable') @@ -463,4 +477,15 @@ public function linkNotAvailableDataProvider() ['addError', 'wrong_status', 'Something went wrong while getting the requested content.'] ]; } + + /** + * @return array + */ + public function downloadTypesDataProvider() + { + return [ + ['mimeType' => 'text/html', 'disposition' => \Zend_Mime::DISPOSITION_ATTACHMENT], + ['mimeType' => 'image/jpeg', 'disposition' => \Zend_Mime::DISPOSITION_INLINE], + ]; + } } diff --git a/app/code/Magento/Downloadable/composer.json b/app/code/Magento/Downloadable/composer.json index 36758eb0a46ff..3642dc98d5965 100644 --- a/app/code/Magento/Downloadable/composer.json +++ b/app/code/Magento/Downloadable/composer.json @@ -25,7 +25,7 @@ "magento/module-downloadable-sample-data": "Sample Data version:100.1.*" }, "type": "magento2-module", - "version": "100.1.4", + "version": "100.1.6", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable/links.phtml b/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable/links.phtml index a3be9e4b3dc43..4b8a3013af519 100644 --- a/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable/links.phtml +++ b/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable/links.phtml @@ -21,7 +21,7 @@
isSingleStoreMode() ? ' data-config-scope="' . __('[STORE VIEW]') . '"' : ''; ?>>
- getStoreId() && $block->getUsedDefault()) ? 'disabled="disabled"' : '' ?>> + getStoreId() && $block->getUsedDefault()) ? 'disabled="disabled"' : '' ?>> getStoreId()): ?>
getUsedDefault() ? 'checked="checked"' : '' ?> /> @@ -158,9 +158,9 @@ require([ ''+ '
'+ '' + - '' + + '' + '"@example.com', + 'sender_email' => '""@example.com', + ], + [ + 'sender' => '"<script>alert(document.domain)</script>"@example.com', + 'sender_email' => '"<script>alert(document.domain)</script>"@example.com', + ], + ], + ]; + } +} diff --git a/app/code/Magento/Newsletter/composer.json b/app/code/Magento/Newsletter/composer.json index 7d0f9734a50f2..c3b6feb158d96 100644 --- a/app/code/Magento/Newsletter/composer.json +++ b/app/code/Magento/Newsletter/composer.json @@ -15,7 +15,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.5", + "version": "100.1.7", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/OfflinePayments/composer.json b/app/code/Magento/OfflinePayments/composer.json index 404e6e9619285..11ee83313d760 100644 --- a/app/code/Magento/OfflinePayments/composer.json +++ b/app/code/Magento/OfflinePayments/composer.json @@ -8,7 +8,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.2", + "version": "100.1.3", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/OfflineShipping/Block/Adminhtml/Form/Field/Export.php b/app/code/Magento/OfflineShipping/Block/Adminhtml/Form/Field/Export.php index cb20cc3139d55..48d6c298aa355 100644 --- a/app/code/Magento/OfflineShipping/Block/Adminhtml/Form/Field/Export.php +++ b/app/code/Magento/OfflineShipping/Block/Adminhtml/Form/Field/Export.php @@ -21,7 +21,7 @@ class Export extends \Magento\Framework\Data\Form\Element\AbstractElement * @param \Magento\Framework\Data\Form\Element\Factory $factoryElement * @param \Magento\Framework\Data\Form\Element\CollectionFactory $factoryCollection * @param \Magento\Framework\Escaper $escaper - * @param \Magento\Backend\Helper\Data $helper + * @param \Magento\Backend\Model\UrlInterface $backendUrl * @param array $data */ public function __construct( diff --git a/app/code/Magento/OfflineShipping/composer.json b/app/code/Magento/OfflineShipping/composer.json index 419e57aaa44ff..be2187077d3dc 100644 --- a/app/code/Magento/OfflineShipping/composer.json +++ b/app/code/Magento/OfflineShipping/composer.json @@ -19,7 +19,7 @@ "magento/module-offline-shipping-sample-data": "Sample Data version:100.1.*" }, "type": "magento2-module", - "version": "100.1.4", + "version": "100.1.5", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/PageCache/composer.json b/app/code/Magento/PageCache/composer.json index 7d789cc753f82..fcf7c90a9a6e8 100644 --- a/app/code/Magento/PageCache/composer.json +++ b/app/code/Magento/PageCache/composer.json @@ -9,7 +9,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.5", + "version": "100.1.6", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Payment/composer.json b/app/code/Magento/Payment/composer.json index 81e7dc53d56de..8adac0125dffc 100644 --- a/app/code/Magento/Payment/composer.json +++ b/app/code/Magento/Payment/composer.json @@ -12,7 +12,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.8", + "version": "100.1.9", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Paypal/Model/Api/Nvp.php b/app/code/Magento/Paypal/Model/Api/Nvp.php index b4417a33ffc46..dcc450a29fd47 100644 --- a/app/code/Magento/Paypal/Model/Api/Nvp.php +++ b/app/code/Magento/Paypal/Model/Api/Nvp.php @@ -1027,7 +1027,7 @@ public function callGetPalDetails() } /** - * Set Customer BillingA greement call + * Set Customer BillingAgreement call * * @return void * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_SetCustomerBillingAgreement @@ -1418,7 +1418,7 @@ protected function _deformatNVP($nvpstr) $nvpstr = strpos($nvpstr, "\r\n\r\n") !== false ? substr($nvpstr, strpos($nvpstr, "\r\n\r\n") + 4) : $nvpstr; while (strlen($nvpstr)) { - //postion of Key + //position of Key $keypos = strpos($nvpstr, '='); //position of value $valuepos = strpos($nvpstr, '&') ? strpos($nvpstr, '&') : strlen($nvpstr); @@ -1426,7 +1426,7 @@ protected function _deformatNVP($nvpstr) /*getting the Key and Value values and storing in a Associative Array*/ $keyval = substr($nvpstr, $intial, $keypos); $valval = substr($nvpstr, $keypos + 1, $valuepos - $keypos - 1); - //decoding the respose + //decoding the response $nvpArray[urldecode($keyval)] = urldecode($valval); $nvpstr = substr($nvpstr, $valuepos + 1, strlen($nvpstr)); } diff --git a/app/code/Magento/Paypal/Model/Express/Checkout.php b/app/code/Magento/Paypal/Model/Express/Checkout.php index 59360f4b0745b..b3dd1af692045 100644 --- a/app/code/Magento/Paypal/Model/Express/Checkout.php +++ b/app/code/Magento/Paypal/Model/Express/Checkout.php @@ -816,7 +816,9 @@ public function place($token, $shippingMethodCode = null) case \Magento\Sales\Model\Order::STATE_PROCESSING: case \Magento\Sales\Model\Order::STATE_COMPLETE: case \Magento\Sales\Model\Order::STATE_PAYMENT_REVIEW: - $this->orderSender->send($order); + if (!$order->getEmailSent()) { + $this->orderSender->send($order); + } $this->_checkoutSession->start(); break; default: diff --git a/app/code/Magento/Paypal/composer.json b/app/code/Magento/Paypal/composer.json index b389927471723..a183129b7d867 100644 --- a/app/code/Magento/Paypal/composer.json +++ b/app/code/Magento/Paypal/composer.json @@ -25,7 +25,7 @@ "magento/module-checkout-agreements": "100.1.*" }, "type": "magento2-module", - "version": "100.1.8", + "version": "100.1.9", "license": [ "proprietary" ], diff --git a/app/code/Magento/Paypal/i18n/en_US.csv b/app/code/Magento/Paypal/i18n/en_US.csv index 56ec49f4eb0d4..4686c4a9004f3 100644 --- a/app/code/Magento/Paypal/i18n/en_US.csv +++ b/app/code/Magento/Paypal/i18n/en_US.csv @@ -348,7 +348,7 @@ expires,expires here,here " to learn more."," to learn more." "Important: ","Important: " -"To use PayPal Payments Advanced, you must configure your PayPal Payments Advanced account on the PayPal website.","To use PayPal Payments Advanced, you must configure your PayPal Payments Advanced account on the PayPal website." +"To use PayPal Payments Advanced, you must configure your PayPal Payments Advanced account on the PayPal website.","To use PayPal Payments Advanced, you must configure your PayPal Payments Advanced account on the PayPal website." "Once you log into your PayPal Advanced account, navigate to the Service Settings - Hosted Checkout Pages - Set Up menu and set the options described below","Once you log into your PayPal Advanced account, navigate to the Service Settings - Hosted Checkout Pages - Set Up menu and set the options described below" "To use PayPal Payflow Link, you must configure your PayPal Payflow Link account on the PayPal website.","To use PayPal Payflow Link, you must configure your PayPal Payflow Link account on the PayPal website." "Once you log into your PayPal Payflow Link account, navigate to the Service Settings - Hosted Checkout Pages - Set Up menu and set the options described below","Once you log into your PayPal Payflow Link account, navigate to the Service Settings - Hosted Checkout Pages - Set Up menu and set the options described below" diff --git a/app/code/Magento/Paypal/view/adminhtml/templates/system/config/payflowlink/advanced.phtml b/app/code/Magento/Paypal/view/adminhtml/templates/system/config/payflowlink/advanced.phtml index 6442ce7c81921..00f9b5e969634 100644 --- a/app/code/Magento/Paypal/view/adminhtml/templates/system/config/payflowlink/advanced.phtml +++ b/app/code/Magento/Paypal/view/adminhtml/templates/system/config/payflowlink/advanced.phtml @@ -12,7 +12,7 @@

escapeHtml(__('Important: ')); ?> - escapeHtml(__('To use PayPal Payments Advanced, you must configure your PayPal Payments Advanced account on the PayPal website.')); ?> + escapeHtml(__('To use PayPal Payments Advanced, you must configure your PayPal Payments Advanced account on the PayPal website.')); ?> escapeHtml(__('Once you log into your PayPal Advanced account, navigate to the Service Settings - Hosted Checkout Pages - Set Up menu and set the options described below')); ?>

    diff --git a/app/code/Magento/Paypal/view/frontend/layout/customer_account.xml b/app/code/Magento/Paypal/view/frontend/layout/customer_account.xml index 5ca352f0b99b7..f6e23632dd4da 100644 --- a/app/code/Magento/Paypal/view/frontend/layout/customer_account.xml +++ b/app/code/Magento/Paypal/view/frontend/layout/customer_account.xml @@ -6,9 +6,6 @@ */ --> - - Billing Agreements - diff --git a/app/code/Magento/Persistent/composer.json b/app/code/Magento/Persistent/composer.json index 1293dce77941f..57a27aa97a61c 100644 --- a/app/code/Magento/Persistent/composer.json +++ b/app/code/Magento/Persistent/composer.json @@ -12,7 +12,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.4", + "version": "100.1.5", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/ProductAlert/composer.json b/app/code/Magento/ProductAlert/composer.json index 1e54998731794..979e006419218 100644 --- a/app/code/Magento/ProductAlert/composer.json +++ b/app/code/Magento/ProductAlert/composer.json @@ -10,7 +10,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/ProductVideo/composer.json b/app/code/Magento/ProductVideo/composer.json index b99745ddc0dff..933e5497d9013 100644 --- a/app/code/Magento/ProductVideo/composer.json +++ b/app/code/Magento/ProductVideo/composer.json @@ -15,7 +15,7 @@ "magento/module-customer": "100.1.*" }, "type": "magento2-module", - "version": "100.1.8", + "version": "100.1.9", "license": [ "proprietary" ], diff --git a/app/code/Magento/Quote/Model/Quote.php b/app/code/Magento/Quote/Model/Quote.php index 9b2ac61ef0989..5e5c356583b16 100644 --- a/app/code/Magento/Quote/Model/Quote.php +++ b/app/code/Magento/Quote/Model/Quote.php @@ -2363,13 +2363,17 @@ public function merge(Quote $quote) * Trigger collect totals after loading, if required * * @return $this + * @throws \Exception */ protected function _afterLoad() { // collect totals and save me, if required if (1 == $this->getData('trigger_recollect')) { - $this->collectTotals()->save(); + $this->collectTotals() + ->setTriggerRecollect(0) + ->save(); } + return parent::_afterLoad(); } diff --git a/app/code/Magento/Quote/composer.json b/app/code/Magento/Quote/composer.json index 1f4931b5a34f6..6849f34d9aa94 100644 --- a/app/code/Magento/Quote/composer.json +++ b/app/code/Magento/Quote/composer.json @@ -20,7 +20,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.7", + "version": "100.1.8", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Reports/composer.json b/app/code/Magento/Reports/composer.json index 47f5a9a03ae8c..968d201d577dc 100644 --- a/app/code/Magento/Reports/composer.json +++ b/app/code/Magento/Reports/composer.json @@ -22,7 +22,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.6", + "version": "100.1.8", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Reports/view/adminhtml/templates/grid.phtml b/app/code/Magento/Reports/view/adminhtml/templates/grid.phtml index b635c5ebdcd5e..677f9c138ec18 100644 --- a/app/code/Magento/Reports/view/adminhtml/templates/grid.phtml +++ b/app/code/Magento/Reports/view/adminhtml/templates/grid.phtml @@ -31,7 +31,7 @@ $numColumns = sizeof($block->getColumns()); type="text" id="getSuffixId('period_date_from') ?>" name="report_from" - value="getFilter('report_from') ?>"> + value="escapeHtml($block->getFilter('report_from')) ?>"> @@ -44,7 +44,7 @@ $numColumns = sizeof($block->getColumns()); type="text" id="getSuffixId('period_date_to') ?>" name="report_to" - value="getFilter('report_to') ?>"/> + value="escapeHtml($block->getFilter('report_to')) ?>"/> diff --git a/app/code/Magento/RequireJs/Model/FileManager.php b/app/code/Magento/RequireJs/Model/FileManager.php index f13e3e050999e..8037fe44ee056 100644 --- a/app/code/Magento/RequireJs/Model/FileManager.php +++ b/app/code/Magento/RequireJs/Model/FileManager.php @@ -164,6 +164,9 @@ public function createBundleJsPool() } foreach ($libDir->read($bundleDir) as $bundleFile) { + if (pathinfo($bundleFile, PATHINFO_EXTENSION) !== 'js') { + continue; + } $relPath = $libDir->getRelativePath($bundleFile); $bundles[] = $this->assetRepo->createArbitrary($relPath, ''); } diff --git a/app/code/Magento/RequireJs/Test/Unit/Model/FileManagerTest.php b/app/code/Magento/RequireJs/Test/Unit/Model/FileManagerTest.php index 057f03edb9ba2..1963c860a5935 100644 --- a/app/code/Magento/RequireJs/Test/Unit/Model/FileManagerTest.php +++ b/app/code/Magento/RequireJs/Test/Unit/Model/FileManagerTest.php @@ -150,7 +150,7 @@ public function testCreateBundleJsPool() ->expects($this->once()) ->method('read') ->with('path/to/bundle/dir/js/bundle') - ->willReturn(['bundle1.js', 'bundle2.js']); + ->willReturn(['bundle1.js', 'bundle2.js', 'some_file.not_js']); $dirRead ->expects($this->exactly(2)) ->method('getRelativePath') diff --git a/app/code/Magento/RequireJs/composer.json b/app/code/Magento/RequireJs/composer.json index 4f0d3028a3b60..3c05a8bf63982 100644 --- a/app/code/Magento/RequireJs/composer.json +++ b/app/code/Magento/RequireJs/composer.json @@ -6,7 +6,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Review/Block/Product/ReviewRenderer.php b/app/code/Magento/Review/Block/Product/ReviewRenderer.php index f60b33bffb8cb..98e6ab9e09289 100644 --- a/app/code/Magento/Review/Block/Product/ReviewRenderer.php +++ b/app/code/Magento/Review/Block/Product/ReviewRenderer.php @@ -18,8 +18,8 @@ class ReviewRenderer extends \Magento\Framework\View\Element\Template implements * @var array */ protected $_availableTemplates = [ - self::FULL_VIEW => 'helper/summary.phtml', - self::SHORT_VIEW => 'helper/summary_short.phtml', + self::FULL_VIEW => 'Magento_Review::helper/summary.phtml', + self::SHORT_VIEW => 'Magento_Review::helper/summary_short.phtml', ]; /** diff --git a/app/code/Magento/Review/Controller/Product.php b/app/code/Magento/Review/Controller/Product.php index 4b8fa5fea92dd..1d2d0a78d8b0c 100644 --- a/app/code/Magento/Review/Controller/Product.php +++ b/app/code/Magento/Review/Controller/Product.php @@ -219,6 +219,11 @@ protected function loadProduct($productId) try { $product = $this->productRepository->getById($productId); + + if (!in_array($this->storeManager->getStore()->getWebsiteId(), $product->getWebsiteIds())) { + throw new NoSuchEntityException(); + } + if (!$product->isVisibleInCatalog() || !$product->isVisibleInSiteVisibility()) { throw new NoSuchEntityException(); } diff --git a/app/code/Magento/Review/Test/Unit/Controller/Product/PostTest.php b/app/code/Magento/Review/Test/Unit/Controller/Product/PostTest.php index e85fdb67c77b6..27902a6b40e65 100644 --- a/app/code/Magento/Review/Test/Unit/Controller/Product/PostTest.php +++ b/app/code/Magento/Review/Test/Unit/Controller/Product/PostTest.php @@ -170,7 +170,13 @@ protected function setUp() $ratingFactory->expects($this->once())->method('create')->willReturn($this->rating); $this->messageManager = $this->getMock('\Magento\Framework\Message\ManagerInterface'); - $this->store = $this->getMock('\Magento\Store\Model\Store', ['getId'], [], '', false); + $this->store = $this->getMock( + '\Magento\Store\Model\Store', + ['getId', 'getWebsiteId'], + [], + '', + false + ); $storeManager = $this->getMockForAbstractClass('\Magento\Store\Model\StoreManagerInterface'); $storeManager->expects($this->any())->method('getStore')->willReturn($this->store); @@ -242,7 +248,7 @@ public function testExecute() ->willReturn(1); $product = $this->getMock( 'Magento\Catalog\Model\Product', - ['__wakeup', 'isVisibleInCatalog', 'isVisibleInSiteVisibility', 'getId'], + ['__wakeup', 'isVisibleInCatalog', 'isVisibleInSiteVisibility', 'getId', 'getWebsiteIds'], [], '', false @@ -253,6 +259,10 @@ public function testExecute() $product->expects($this->once()) ->method('isVisibleInSiteVisibility') ->willReturn(true); + $product->expects($this->once()) + ->method('getWebsiteIds') + ->willReturn([1]); + $this->productRepository->expects($this->any())->method('getById') ->with(1) ->willReturn($product); @@ -288,6 +298,8 @@ public function testExecute() $this->review->expects($this->once())->method('setCustomerId')->with($customerId)->willReturnSelf(); $this->store->expects($this->exactly(2))->method('getId') ->willReturn($storeId); + $this->store->expects($this->once())->method('getWebsiteId') + ->willReturn(1); $this->review->expects($this->once())->method('setStoreId') ->with($storeId) ->willReturnSelf(); diff --git a/app/code/Magento/Review/composer.json b/app/code/Magento/Review/composer.json index dcd2efe345852..4bb76ead4a548 100644 --- a/app/code/Magento/Review/composer.json +++ b/app/code/Magento/Review/composer.json @@ -18,7 +18,7 @@ "magento/module-review-sample-data": "Sample Data version:100.1.*" }, "type": "magento2-module", - "version": "100.1.5", + "version": "100.1.7", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Review/i18n/en_US.csv b/app/code/Magento/Review/i18n/en_US.csv index b27c7b1a99684..547bfe9f3df2f 100644 --- a/app/code/Magento/Review/i18n/en_US.csv +++ b/app/code/Magento/Review/i18n/en_US.csv @@ -131,3 +131,5 @@ Summary,Summary "Allow Guests to Write Reviews","Allow Guests to Write Reviews" Active,Active Inactive,Inactive +star,star +stars,stars diff --git a/app/code/Magento/Review/view/adminhtml/web/js/rating.js b/app/code/Magento/Review/view/adminhtml/web/js/rating.js index 35f32e4a23ef5..22019179771c5 100644 --- a/app/code/Magento/Review/view/adminhtml/web/js/rating.js +++ b/app/code/Magento/Review/view/adminhtml/web/js/rating.js @@ -23,7 +23,7 @@ define([ _bind: function() { this._labels.on({ click: $.proxy(function(e) { - $('[id="' + $(e.currentTarget).attr('for') + '"]').prop('checked', true); + $(e.currentTarget).prev().prop('checked', true); this._updateRating(); }, this), diff --git a/app/code/Magento/Review/view/frontend/templates/form.phtml b/app/code/Magento/Review/view/frontend/templates/form.phtml index 23d1bfd041404..80f552d292034 100644 --- a/app/code/Magento/Review/view/frontend/templates/form.phtml +++ b/app/code/Magento/Review/view/frontend/templates/form.phtml @@ -42,9 +42,9 @@ diff --git a/app/code/Magento/Review/view/frontend/templates/redirect.phtml b/app/code/Magento/Review/view/frontend/templates/redirect.phtml index fc74cadacb319..2fdb5e90a9c18 100644 --- a/app/code/Magento/Review/view/frontend/templates/redirect.phtml +++ b/app/code/Magento/Review/view/frontend/templates/redirect.phtml @@ -8,9 +8,6 @@ ?> getProduct()->getProductUrl()}#info-product_reviews"); exit; ?> diff --git a/app/code/Magento/Review/view/frontend/templates/view.phtml b/app/code/Magento/Review/view/frontend/templates/view.phtml index 60551aa9c0319..3bb66580319b1 100644 --- a/app/code/Magento/Review/view/frontend/templates/view.phtml +++ b/app/code/Magento/Review/view/frontend/templates/view.phtml @@ -49,7 +49,7 @@
    - +
    diff --git a/app/code/Magento/Robots/Controller/Index/Index.php b/app/code/Magento/Robots/Controller/Index/Index.php index b94626e93432d..679066d723dce 100644 --- a/app/code/Magento/Robots/Controller/Index/Index.php +++ b/app/code/Magento/Robots/Controller/Index/Index.php @@ -43,6 +43,7 @@ public function execute() /** @var Page $resultPage */ $resultPage = $this->resultPageFactory->create(true); $resultPage->addHandle('robots_index_index'); + $resultPage->setHeader('Content-Type', 'text/plain'); return $resultPage; } } diff --git a/app/code/Magento/Robots/Test/Unit/Controller/Index/IndexTest.php b/app/code/Magento/Robots/Test/Unit/Controller/Index/IndexTest.php index aaac511e3c521..3ebf1d05325c5 100644 --- a/app/code/Magento/Robots/Test/Unit/Controller/Index/IndexTest.php +++ b/app/code/Magento/Robots/Test/Unit/Controller/Index/IndexTest.php @@ -51,6 +51,9 @@ public function testExecute() $resultPageMock->expects($this->once()) ->method('addHandle') ->with('robots_index_index'); + $resultPageMock->expects($this->once()) + ->method('setHeader') + ->with('Content-Type', 'text/plain'); $this->resultPageFactory->expects($this->any()) ->method('create') diff --git a/app/code/Magento/Robots/composer.json b/app/code/Magento/Robots/composer.json index 218a59138d998..a23211c6fa5d3 100644 --- a/app/code/Magento/Robots/composer.json +++ b/app/code/Magento/Robots/composer.json @@ -10,7 +10,7 @@ "magento/module-theme": "100.1.*" }, "type": "magento2-module", - "version": "100.1.0", + "version": "100.1.1", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Rss/composer.json b/app/code/Magento/Rss/composer.json index 2202ad5ceabfd..dec7ee02e5196 100644 --- a/app/code/Magento/Rss/composer.json +++ b/app/code/Magento/Rss/composer.json @@ -9,7 +9,7 @@ "magento/module-customer": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Rule/composer.json b/app/code/Magento/Rule/composer.json index 5744235ab0bd8..18b3ac2ee98d9 100644 --- a/app/code/Magento/Rule/composer.json +++ b/app/code/Magento/Rule/composer.json @@ -11,7 +11,7 @@ "lib-libxml": "*" }, "type": "magento2-module", - "version": "100.1.7", + "version": "100.1.8", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php b/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php index 0d78947cd523e..df674a93794c1 100644 --- a/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php +++ b/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php @@ -13,6 +13,7 @@ use Magento\Sales\Model\ResourceModel\Order as OrderResource; use Magento\Sales\Model\Order\Address\Renderer; use Magento\Framework\Event\ManagerInterface; +use Magento\Framework\DataObject; /** * Class OrderSender @@ -127,14 +128,17 @@ protected function prepareTemplate(Order $order) 'formattedShippingAddress' => $this->getFormattedShippingAddress($order), 'formattedBillingAddress' => $this->getFormattedBillingAddress($order), ]; - $transport = new \Magento\Framework\DataObject($transport); + $transportObject = new DataObject($transport); + /** + * Event argument `transport` is @deprecated. Use `transportObject` instead. + */ $this->eventManager->dispatch( 'email_order_set_template_vars_before', - ['sender' => $this, 'transport' => $transport] + ['sender' => $this, 'transport' => $transportObject->getData(), 'transportObject' => $transportObject] ); - $this->templateContainer->setTemplateVars($transport->getData()); + $this->templateContainer->setTemplateVars($transportObject->getData()); parent::prepareTemplate($order); } diff --git a/app/code/Magento/Sales/Model/Order/Pdf/AbstractPdf.php b/app/code/Magento/Sales/Model/Order/Pdf/AbstractPdf.php index b5477c6de8d4d..6e836bae1e215 100644 --- a/app/code/Magento/Sales/Model/Order/Pdf/AbstractPdf.php +++ b/app/code/Magento/Sales/Model/Order/Pdf/AbstractPdf.php @@ -851,7 +851,7 @@ protected function _drawItem(\Magento\Framework\DataObject $item, \Zend_Pdf_Page protected function _setFontRegular($object, $size = 7) { $font = \Zend_Pdf_Font::fontWithPath( - $this->_rootDirectory->getAbsolutePath('lib/internal/LinLibertineFont/LinLibertine_Re-4.4.1.ttf') + $this->_rootDirectory->getAbsolutePath('lib/internal/GnuFreeFont/FreeSerif.ttf') ); $object->setFont($font, $size); return $font; @@ -867,7 +867,7 @@ protected function _setFontRegular($object, $size = 7) protected function _setFontBold($object, $size = 7) { $font = \Zend_Pdf_Font::fontWithPath( - $this->_rootDirectory->getAbsolutePath('lib/internal/LinLibertineFont/LinLibertine_Bd-2.8.1.ttf') + $this->_rootDirectory->getAbsolutePath('lib/internal/GnuFreeFont/FreeSerifBold.ttf') ); $object->setFont($font, $size); return $font; @@ -883,7 +883,7 @@ protected function _setFontBold($object, $size = 7) protected function _setFontItalic($object, $size = 7) { $font = \Zend_Pdf_Font::fontWithPath( - $this->_rootDirectory->getAbsolutePath('lib/internal/LinLibertineFont/LinLibertine_It-2.8.2.ttf') + $this->_rootDirectory->getAbsolutePath('lib/internal/GnuFreeFont/FreeSerifItalic.ttf') ); $object->setFont($font, $size); return $font; diff --git a/app/code/Magento/Sales/Model/Order/Pdf/Items/AbstractItems.php b/app/code/Magento/Sales/Model/Order/Pdf/Items/AbstractItems.php index ce63d77f1d5d7..15d1a83dfd313 100644 --- a/app/code/Magento/Sales/Model/Order/Pdf/Items/AbstractItems.php +++ b/app/code/Magento/Sales/Model/Order/Pdf/Items/AbstractItems.php @@ -335,7 +335,7 @@ public function getItemOptions() protected function _setFontRegular($size = 7) { $font = \Zend_Pdf_Font::fontWithPath( - $this->_rootDirectory->getAbsolutePath('lib/internal/LinLibertineFont/LinLibertine_Re-4.4.1.ttf') + $this->_rootDirectory->getAbsolutePath('lib/internal/GnuFreeFont/FreeSerif.ttf') ); $this->getPage()->setFont($font, $size); return $font; @@ -350,7 +350,7 @@ protected function _setFontRegular($size = 7) protected function _setFontBold($size = 7) { $font = \Zend_Pdf_Font::fontWithPath( - $this->_rootDirectory->getAbsolutePath('lib/internal/LinLibertineFont/LinLibertine_Bd-2.8.1.ttf') + $this->_rootDirectory->getAbsolutePath('lib/internal/GnuFreeFont/FreeSerifBold.ttf') ); $this->getPage()->setFont($font, $size); return $font; @@ -365,7 +365,7 @@ protected function _setFontBold($size = 7) protected function _setFontItalic($size = 7) { $font = \Zend_Pdf_Font::fontWithPath( - $this->_rootDirectory->getAbsolutePath('lib/internal/LinLibertineFont/LinLibertine_It-2.8.2.ttf') + $this->_rootDirectory->getAbsolutePath('lib/internal/GnuFreeFont/FreeSerifItalic.ttf') ); $this->getPage()->setFont($font, $size); return $font; diff --git a/app/code/Magento/Sales/Model/Order/Shipment/Item.php b/app/code/Magento/Sales/Model/Order/Shipment/Item.php index e2ba72a870c33..64a1562da8739 100644 --- a/app/code/Magento/Sales/Model/Order/Shipment/Item.php +++ b/app/code/Magento/Sales/Model/Order/Shipment/Item.php @@ -146,8 +146,7 @@ public function getOrderItem() * Declare qty * * @param float $qty - * @return \Magento\Sales\Model\Order\Invoice\Item - * @throws \Magento\Framework\Exception\LocalizedException + * @return $this */ public function setQty($qty) { @@ -159,7 +158,6 @@ public function setQty($qty) * Applying qty to order item * * @return $this - * @throws \Magento\Framework\Exception\LocalizedException */ public function register() { diff --git a/app/code/Magento/Sales/Model/ResourceModel/Grid/Collection.php b/app/code/Magento/Sales/Model/ResourceModel/Grid/Collection.php index e6aafb07a0c87..1c7e4f0eec75d 100644 --- a/app/code/Magento/Sales/Model/ResourceModel/Grid/Collection.php +++ b/app/code/Magento/Sales/Model/ResourceModel/Grid/Collection.php @@ -6,7 +6,7 @@ namespace Magento\Sales\Model\ResourceModel\Grid; use Magento\Framework\Api\Search\SearchResultInterface; -use Magento\Framework\Search\AggregationInterface; +use Magento\Framework\Api\Search\AggregationInterface; use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; /** @@ -15,7 +15,6 @@ */ class Collection extends AbstractCollection implements SearchResultInterface { - /** * @var AggregationInterface */ @@ -78,9 +77,9 @@ public function getAggregations() public function setAggregations($aggregations) { $this->aggregations = $aggregations; + return $this; } - /** * Retrieve all ids for collection * Backward compatibility with EAV collection diff --git a/app/code/Magento/Sales/composer.json b/app/code/Magento/Sales/composer.json index 4e54681e1525f..d39a344ce9ca3 100644 --- a/app/code/Magento/Sales/composer.json +++ b/app/code/Magento/Sales/composer.json @@ -32,7 +32,7 @@ "magento/module-sales-sample-data": "Sample Data version:100.1.*" }, "type": "magento2-module", - "version": "100.1.10", + "version": "100.1.11", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml index 69adf252a9b1d..fbb9d028c4f04 100644 --- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml +++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml @@ -187,7 +187,6 @@ date Purchase Date desc - MMM dd, YYYY, H:mm:ss A diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml index ccb1faae5e8a8..e3c6e680da1f2 100644 --- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml +++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml @@ -34,7 +34,15 @@ - + + + + + * + + + + diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_invoice_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_invoice_grid.xml index 559254387875c..5663bca048995 100644 --- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_invoice_grid.xml +++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_invoice_grid.xml @@ -34,7 +34,15 @@ - + + + + + * + + + + diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_shipment_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_shipment_grid.xml index 12cdd55a5f9fe..006318b00221b 100644 --- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_shipment_grid.xml +++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_shipment_grid.xml @@ -34,7 +34,15 @@ - + + + + + * + + + + diff --git a/app/code/Magento/SalesInventory/composer.json b/app/code/Magento/SalesInventory/composer.json index 783382f0d4af6..1efbde227d20c 100644 --- a/app/code/Magento/SalesInventory/composer.json +++ b/app/code/Magento/SalesInventory/composer.json @@ -10,7 +10,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.1", + "version": "100.1.2", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote.php b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote.php index 2b788d36acb0c..d58c8220813ef 100644 --- a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote.php +++ b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote.php @@ -74,7 +74,7 @@ protected function _initRule() /** * Initiate action * - * @return this + * @return $this */ protected function _initAction() { diff --git a/app/code/Magento/SalesRule/Model/ResourceModel/Coupon.php b/app/code/Magento/SalesRule/Model/ResourceModel/Coupon.php index 5068f53f23bc9..3907261cad1b9 100644 --- a/app/code/Magento/SalesRule/Model/ResourceModel/Coupon.php +++ b/app/code/Magento/SalesRule/Model/ResourceModel/Coupon.php @@ -106,7 +106,7 @@ public function exists($code) } /** - * Update auto generated Specific Coupon if it's rule changed + * Update auto generated Specific Coupon if its rule changed * * @param \Magento\SalesRule\Model\Rule $rule * @return $this diff --git a/app/code/Magento/SalesRule/composer.json b/app/code/Magento/SalesRule/composer.json index 77bca4537aeaf..ce3923b8c648c 100644 --- a/app/code/Magento/SalesRule/composer.json +++ b/app/code/Magento/SalesRule/composer.json @@ -25,7 +25,7 @@ "magento/module-sales-rule-sample-data": "Sample Data version:100.1.*" }, "type": "magento2-module", - "version": "100.1.6", + "version": "100.1.7", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/SalesSequence/composer.json b/app/code/Magento/SalesSequence/composer.json index 32397fa0399c3..c51e9704c051a 100644 --- a/app/code/Magento/SalesSequence/composer.json +++ b/app/code/Magento/SalesSequence/composer.json @@ -6,7 +6,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/SampleData/composer.json b/app/code/Magento/SampleData/composer.json index 99d41c91d09ef..07f6d6e7cd3e6 100644 --- a/app/code/Magento/SampleData/composer.json +++ b/app/code/Magento/SampleData/composer.json @@ -9,7 +9,7 @@ "magento/sample-data-media": "Sample Data version:100.1.*" }, "type": "magento2-module", - "version": "100.1.4", + "version": "100.1.5", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Search/composer.json b/app/code/Magento/Search/composer.json index c8ffd9323e561..d3fd9854b5f1a 100644 --- a/app/code/Magento/Search/composer.json +++ b/app/code/Magento/Search/composer.json @@ -11,7 +11,7 @@ "magento/module-ui": "100.1.*" }, "type": "magento2-module", - "version": "100.1.4", + "version": "100.1.5", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Security/Model/AdminSessionInfo.php b/app/code/Magento/Security/Model/AdminSessionInfo.php index 2da74ce7689b2..2a66aaad80cf7 100644 --- a/app/code/Magento/Security/Model/AdminSessionInfo.php +++ b/app/code/Magento/Security/Model/AdminSessionInfo.php @@ -154,7 +154,7 @@ public function isOtherSessionsTerminated() * Setter for isOtherSessionsTerminated * * @param bool $isOtherSessionsTerminated - * @return this + * @return $this */ public function setIsOtherSessionsTerminated($isOtherSessionsTerminated) { diff --git a/app/code/Magento/Security/composer.json b/app/code/Magento/Security/composer.json index 0bd8008b96689..a20481d091c6e 100644 --- a/app/code/Magento/Security/composer.json +++ b/app/code/Magento/Security/composer.json @@ -11,7 +11,7 @@ "magento/module-customer": "100.1.*" }, "type": "magento2-module", - "version": "100.1.3", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Security/etc/adminhtml/di.xml b/app/code/Magento/Security/etc/adminhtml/di.xml index c1188c2d405cf..79477e9443097 100644 --- a/app/code/Magento/Security/etc/adminhtml/di.xml +++ b/app/code/Magento/Security/etc/adminhtml/di.xml @@ -24,7 +24,7 @@ Magento\Security\Model\SecurityChecker\Frequency - Magento\Security\Model\SecurityChecker\Quantity + Magento\Security\Model\SecurityChecker\Quantity diff --git a/app/code/Magento/SendFriend/composer.json b/app/code/Magento/SendFriend/composer.json index afda90dea6059..523ee5de43b42 100644 --- a/app/code/Magento/SendFriend/composer.json +++ b/app/code/Magento/SendFriend/composer.json @@ -10,7 +10,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.2", + "version": "100.1.3", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Shipping/Model/Info.php b/app/code/Magento/Shipping/Model/Info.php index ec03d06c5b2d1..718edbce83b8c 100644 --- a/app/code/Magento/Shipping/Model/Info.php +++ b/app/code/Magento/Shipping/Model/Info.php @@ -116,7 +116,7 @@ protected function _initOrder() /** @var \Magento\Sales\Model\Order $order */ $order = $this->_orderFactory->create()->load($this->getOrderId()); - if (!$order->getId() || $this->getProtectCode() != $order->getProtectCode()) { + if (!$order->getId() || $this->getProtectCode() !== $order->getProtectCode()) { return false; } @@ -132,7 +132,7 @@ protected function _initShipment() { /* @var $model Shipment */ $ship = $this->shipmentRepository->get($this->getShipId()); - if (!$ship->getEntityId() || $this->getProtectCode() != $ship->getProtectCode()) { + if (!$ship->getEntityId() || $this->getProtectCode() !== $ship->getProtectCode()) { return false; } @@ -197,7 +197,7 @@ public function getTrackingInfoByTrackId() { /** @var \Magento\Shipping\Model\Order\Track $track */ $track = $this->_trackFactory->create()->load($this->getTrackId()); - if ($track->getId() && $this->getProtectCode() == $track->getProtectCode()) { + if ($track->getId() && $this->getProtectCode() === $track->getProtectCode()) { $this->_trackingInfo = [[$track->getNumberDetail()]]; } return $this->_trackingInfo; diff --git a/app/code/Magento/Shipping/Test/Unit/Model/InfoTest.php b/app/code/Magento/Shipping/Test/Unit/Model/InfoTest.php new file mode 100644 index 0000000000000..3fe2f1e14448b --- /dev/null +++ b/app/code/Magento/Shipping/Test/Unit/Model/InfoTest.php @@ -0,0 +1,300 @@ +helper = $this->getMockBuilder(\Magento\Shipping\Helper\Data::class) + ->disableOriginalConstructor() + ->getMock(); + $this->orderFactory = $this->getMockBuilder(\Magento\Sales\Model\OrderFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->shipmentRepository = $this->getMockBuilder(\Magento\Sales\Api\ShipmentRepositoryInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->trackFactory = $this->getMockBuilder(\Magento\Shipping\Model\Order\TrackFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->trackCollectionFactory = $this->getMockBuilder(CollectionFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $objectManagerHelper = new ObjectManager($this); + $this->info = $objectManagerHelper->getObject( + Info::class, + [ + 'shippingData' => $this->helper, + 'orderFactory' => $this->orderFactory, + 'shipmentRepository' => $this->shipmentRepository, + 'trackFactory' => $this->trackFactory, + 'trackCollectionFactory' => $this->trackCollectionFactory, + ] + ); + } + + public function testLoadByHashWithOrderId() + { + $hash = strtr(base64_encode('order_id:1:protected_code'), '+/=', '-_,'); + $decodedHash = [ + 'key' => 'order_id', + 'id' => 1, + 'hash' => 'protected_code', + ]; + $shipmentId = 1; + $shipmentIncrementId = 3; + $trackDetails = 'track_details'; + + $this->helper->expects($this->atLeastOnce()) + ->method('decodeTrackingHash') + ->with($hash) + ->willReturn($decodedHash); + $shipmentCollection = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Shipment\Collection::class) + ->disableOriginalConstructor() + ->setMethods(['getIterator']) + ->getMock(); + $order = $this->getMockBuilder(\Magento\Sales\Model\Order::class) + ->disableOriginalConstructor() + ->setMethods(['load', 'getId', 'getProtectCode', 'getShipmentsCollection']) + ->getMock(); + $order->expects($this->atLeastOnce())->method('load')->with($decodedHash['id'])->willReturnSelf(); + $order->expects($this->atLeastOnce())->method('getId')->willReturn($decodedHash['id']); + $order->expects($this->atLeastOnce())->method('getProtectCode')->willReturn($decodedHash['hash']); + $order->expects($this->atLeastOnce())->method('getShipmentsCollection')->willReturn($shipmentCollection); + + $shipment = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment::class) + ->disableOriginalConstructor() + ->setMethods(['getIncrementId', 'getId']) + ->getMock(); + $shipment->expects($this->atLeastOnce())->method('getIncrementId')->willReturn($shipmentIncrementId); + $shipment->expects($this->atLeastOnce())->method('getId')->willReturn($shipmentId); + + $shipmentCollection->expects($this->any())->method('getIterator')->willReturn(new \ArrayIterator([$shipment])); + $this->orderFactory->expects($this->atLeastOnce())->method('create')->willReturn($order); + $track = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment\Track::class) + ->disableOriginalConstructor() + ->setMethods(['setShipment', 'getNumberDetail']) + ->getMock(); + $track->expects($this->atLeastOnce())->method('setShipment')->with($shipment)->willReturnSelf(); + $track->expects($this->atLeastOnce())->method('getNumberDetail')->willReturn($trackDetails); + $trackCollection = $this->getMockBuilder(\Magento\Shipping\Model\ResourceModel\Order\Track\Collection::class) + ->disableOriginalConstructor() + ->setMethods(['getIterator', 'setShipmentFilter']) + ->getMock(); + $trackCollection->expects($this->atLeastOnce()) + ->method('setShipmentFilter') + ->with($shipmentId) + ->willReturnSelf(); + $trackCollection->expects($this->atLeastOnce()) + ->method('getIterator') + ->willReturn(new \ArrayIterator([$track])); + $this->trackCollectionFactory->expects($this->atLeastOnce())->method('create')->willReturn($trackCollection); + + $this->info->loadByHash($hash); + $this->assertEquals([$shipmentIncrementId => [$trackDetails]], $this->info->getTrackingInfo()); + } + + public function testLoadByHashWithOrderIdWrongCode() + { + $hash = strtr(base64_encode('order_id:1:0'), '+/=', '-_,'); + $decodedHash = [ + 'key' => 'order_id', + 'id' => 1, + 'hash' => '0', + ]; + + $this->helper->expects($this->atLeastOnce()) + ->method('decodeTrackingHash') + ->with($hash) + ->willReturn($decodedHash); + $order = $this->getMockBuilder(\Magento\Sales\Model\Order::class) + ->disableOriginalConstructor() + ->setMethods(['load', 'getId', 'getProtectCode', 'getShipmentsCollection']) + ->getMock(); + $order->expects($this->atLeastOnce())->method('load')->with($decodedHash['id'])->willReturnSelf(); + $order->expects($this->atLeastOnce())->method('getId')->willReturn($decodedHash['id']); + $order->expects($this->atLeastOnce())->method('getProtectCode')->willReturn('0e123123123'); + $this->orderFactory->expects($this->atLeastOnce())->method('create')->willReturn($order); + $this->info->loadByHash($hash); + $this->assertEmpty($this->info->getTrackingInfo()); + } + + public function testLoadByHashWithShipmentId() + { + $hash = strtr(base64_encode('ship_id:1:protected_code'), '+/=', '-_,'); + $decodedHash = [ + 'key' => 'ship_id', + 'id' => 1, + 'hash' => 'protected_code', + ]; + $shipmentIncrementId = 3; + $trackDetails = 'track_details'; + + $this->helper->expects($this->atLeastOnce()) + ->method('decodeTrackingHash') + ->with($hash) + ->willReturn($decodedHash); + $shipment = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment::class) + ->disableOriginalConstructor() + ->setMethods(['getEntityId', 'getProtectCode', 'getIncrementId', 'getId']) + ->getMock(); + $shipment->expects($this->atLeastOnce())->method('getIncrementId')->willReturn($shipmentIncrementId); + $shipment->expects($this->atLeastOnce())->method('getId')->willReturn($decodedHash['id']); + $shipment->expects($this->atLeastOnce())->method('getEntityId')->willReturn(3); + $shipment->expects($this->atLeastOnce())->method('getProtectCode')->willReturn($decodedHash['hash']); + $this->shipmentRepository->expects($this->atLeastOnce()) + ->method('get') + ->with($decodedHash['id']) + ->willReturn($shipment); + $track = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment\Track::class) + ->disableOriginalConstructor() + ->setMethods(['setShipment', 'getNumberDetail']) + ->getMock(); + $track->expects($this->atLeastOnce())->method('setShipment')->with($shipment)->willReturnSelf(); + $track->expects($this->atLeastOnce())->method('getNumberDetail')->willReturn($trackDetails); + $trackCollection = $this->getMockBuilder(\Magento\Shipping\Model\ResourceModel\Order\Track\Collection::class) + ->disableOriginalConstructor() + ->setMethods(['getIterator', 'setShipmentFilter']) + ->getMock(); + $trackCollection->expects($this->atLeastOnce()) + ->method('setShipmentFilter') + ->with($decodedHash['id']) + ->willReturnSelf(); + $trackCollection->expects($this->atLeastOnce()) + ->method('getIterator') + ->willReturn(new \ArrayIterator([$track])); + $this->trackCollectionFactory->expects($this->atLeastOnce())->method('create')->willReturn($trackCollection); + + $this->info->loadByHash($hash); + $this->assertEquals([$shipmentIncrementId => [$trackDetails]], $this->info->getTrackingInfo()); + } + + public function testLoadByHashWithShipmentIdWrongCode() + { + $hash = strtr(base64_encode('ship_id:1:0'), '+/=', '-_,'); + $decodedHash = [ + 'key' => 'ship_id', + 'id' => 1, + 'hash' => '0', + ]; + + $this->helper->expects($this->atLeastOnce()) + ->method('decodeTrackingHash') + ->with($hash) + ->willReturn($decodedHash); + $shipment = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment::class) + ->disableOriginalConstructor() + ->setMethods(['getEntityId', 'getProtectCode', 'getIncrementId', 'getId']) + ->getMock(); + $shipment->expects($this->atLeastOnce())->method('getEntityId')->willReturn(3); + $shipment->expects($this->atLeastOnce())->method('getProtectCode')->willReturn('0e123123123'); + $this->shipmentRepository->expects($this->atLeastOnce()) + ->method('get') + ->with($decodedHash['id']) + ->willReturn($shipment); + + $this->info->loadByHash($hash); + $this->assertEmpty($this->info->getTrackingInfo()); + } + + public function testLoadByHashWithTrackId() + { + $hash = base64_encode('hash'); + $decodedHash = [ + 'key' => 'track_id', + 'id' => 1, + 'hash' => 'protected_code', + ]; + $trackDetails = 'track_details'; + $this->helper->expects($this->atLeastOnce()) + ->method('decodeTrackingHash') + ->with($hash) + ->willReturn($decodedHash); + $track = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment\Track::class) + ->disableOriginalConstructor() + ->setMethods(['load', 'getId', 'getProtectCode', 'getNumberDetail']) + ->getMock(); + $track->expects($this->atLeastOnce())->method('load')->with($decodedHash['id'])->willReturnSelf(); + $track->expects($this->atLeastOnce())->method('getId')->willReturn($decodedHash['id']); + $track->expects($this->atLeastOnce())->method('getProtectCode')->willReturn($decodedHash['hash']); + $track->expects($this->atLeastOnce())->method('getNumberDetail')->willReturn($trackDetails); + $this->trackFactory->expects($this->atLeastOnce())->method('create')->willReturn($track); + + $this->info->loadByHash($hash); + $this->assertEquals([[$trackDetails]], $this->info->getTrackingInfo()); + } + + public function testLoadByHashWithWrongCode() + { + $hash = base64_encode('hash'); + $decodedHash = [ + 'key' => 'track_id', + 'id' => 1, + 'hash' => 'protected_code', + ]; + $this->helper->expects($this->atLeastOnce()) + ->method('decodeTrackingHash') + ->with($hash) + ->willReturn($decodedHash); + $track = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment\Track::class) + ->disableOriginalConstructor() + ->setMethods(['load', 'getId', 'getProtectCode', 'getNumberDetail']) + ->getMock(); + $track->expects($this->atLeastOnce())->method('load')->with($decodedHash['id'])->willReturnSelf(); + $track->expects($this->atLeastOnce())->method('getId')->willReturn($decodedHash['id']); + $track->expects($this->atLeastOnce())->method('getProtectCode')->willReturn('0e123123123'); + $this->trackFactory->expects($this->atLeastOnce())->method('create')->willReturn($track); + + $this->info->loadByHash($hash); + $this->assertEmpty($this->info->getTrackingInfo()); + } +} diff --git a/app/code/Magento/Shipping/composer.json b/app/code/Magento/Shipping/composer.json index a51856c0c04bd..58c58ab4f5555 100644 --- a/app/code/Magento/Shipping/composer.json +++ b/app/code/Magento/Shipping/composer.json @@ -24,7 +24,7 @@ "magento/module-ups": "100.1.*" }, "type": "magento2-module", - "version": "100.1.5", + "version": "100.1.7", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Shipping/view/adminhtml/templates/view/form.phtml b/app/code/Magento/Shipping/view/adminhtml/templates/view/form.phtml index 3f8c95320a861..9db675694578b 100644 --- a/app/code/Magento/Shipping/view/adminhtml/templates/view/form.phtml +++ b/app/code/Magento/Shipping/view/adminhtml/templates/view/form.phtml @@ -6,70 +6,78 @@ // @codingStandardsIgnoreFile +/** + * @var \Magento\Shipping\Block\Adminhtml\View\Form $block + */ +$order = $block->getShipment()->getOrder(); ?> -getShipment()->getOrder() ?> -getChildHtml('order_info') ?> +getChildHtml('order_info'); ?>
    - + escapeHtml(__('Payment & Shipping Method')); ?>
    - + escapeHtml(__('Payment Information')); ?>
    -
    getChildHtml('order_payment') ?>
    -
    getOrderCurrencyCode()) ?>
    +
    getChildHtml('order_payment'); ?>
    +
    + escapeHtml(__('The order was placed using %1.', $order->getOrderCurrencyCode())); ?> +
    - + escapeHtml(__('Shipping and Tracking Information')); ?>
    getShipment()->getTracksCollection()->count()): ?>

    - + + escapeHtml(__('Track this shipment')); ?>

    - escapeHtml($_order->getShippingDescription()) ?> + escapeHtml($order->getShippingDescription()) ?>
    - : + escapeHtml(__('Total Shipping Charges')); ?>: - helper('Magento\Tax\Helper\Data')->displayShippingPriceIncludingTax()): ?> - displayShippingPriceInclTax($_order); ?> + helper(\Magento\Tax\Helper\Data::class)->displayShippingPriceIncludingTax()): ?> + displayShippingPriceInclTax($order); ?> - displayPriceAttribute('shipping_amount', false, ' '); ?> + displayPriceAttribute('shipping_amount', false, ' '); ?> - displayShippingPriceInclTax($_order); ?> + displayShippingPriceInclTax($order); ?> - - helper('Magento\Tax\Helper\Data')->displayShippingBothPrices() && $_incl != $_excl): ?> - ( ) + + helper(\Magento\Tax\Helper\Data::class)->displayShippingBothPrices() && $incl != $excl): ?> + (escapeHtml(__('Incl. Tax')); ?> )
    - canCreateShippingLabel()): ?>

    - getCreateLabelButton()?> + canCreateShippingLabel()): ?> + getCreateLabelButton(); ?> + getShipment()->getShippingLabel()): ?> - getPrintLabelButton() ?> + getPrintLabelButton(); ?> getShipment()->getPackages()): ?> - getShowPackagesButton() ?> + getShowPackagesButton(); ?>

    - - getChildHtml('shipment_tracking') ?> + getChildHtml('shipment_tracking'); ?> - getChildHtml('shipment_packaging') ?> + getChildHtml('shipment_packaging'); ?> diff --git a/app/code/Magento/SwatchesLayeredNavigation/composer.json b/app/code/Magento/SwatchesLayeredNavigation/composer.json index 11dd456885353..99823150e378d 100644 --- a/app/code/Magento/SwatchesLayeredNavigation/composer.json +++ b/app/code/Magento/SwatchesLayeredNavigation/composer.json @@ -7,7 +7,7 @@ "magento/magento-composer-installer": "*" }, "type": "magento2-module", - "version": "100.1.2", + "version": "100.1.3", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Tax/Model/Config.php b/app/code/Magento/Tax/Model/Config.php index 713b34c16d1f2..64f5b44803848 100644 --- a/app/code/Magento/Tax/Model/Config.php +++ b/app/code/Magento/Tax/Model/Config.php @@ -831,12 +831,12 @@ public function getInfoUrl($store = null) * If it necessary will be returned conversion type (minus or plus) * * @param null|int|string|Store $store - * @return bool + * @return bool|int * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function needPriceConversion($store = null) { - $res = false; + $res = 0; $priceIncludesTax = $this->priceIncludesTax($store) || $this->getNeedUseShippingExcludeTax(); if ($priceIncludesTax) { switch ($this->getPriceDisplayType($store)) { @@ -844,7 +844,7 @@ public function needPriceConversion($store = null) case self::DISPLAY_TYPE_BOTH: return self::PRICE_CONVERSION_MINUS; case self::DISPLAY_TYPE_INCLUDING_TAX: - $res = true; + $res = false; break; default: break; diff --git a/app/code/Magento/Tax/composer.json b/app/code/Magento/Tax/composer.json index 75e91ef3e2cac..67a656e47e083 100644 --- a/app/code/Magento/Tax/composer.json +++ b/app/code/Magento/Tax/composer.json @@ -22,7 +22,7 @@ "magento/module-tax-sample-data": "Sample Data version:100.1.*" }, "type": "magento2-module", - "version": "100.1.4", + "version": "100.1.5", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/TaxImportExport/composer.json b/app/code/Magento/TaxImportExport/composer.json index 184b545ec06b0..21f645b3dc3ab 100644 --- a/app/code/Magento/TaxImportExport/composer.json +++ b/app/code/Magento/TaxImportExport/composer.json @@ -10,7 +10,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.2", + "version": "100.1.3", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Theme/composer.json b/app/code/Magento/Theme/composer.json index 61a8e728e2236..a3cfa4cbe9b4a 100644 --- a/app/code/Magento/Theme/composer.json +++ b/app/code/Magento/Theme/composer.json @@ -21,7 +21,7 @@ "magento/module-theme-sample-data": "Sample Data version:100.1.*" }, "type": "magento2-module", - "version": "100.1.9", + "version": "100.1.10", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Theme/view/frontend/templates/html/print.phtml b/app/code/Magento/Theme/view/frontend/templates/html/print.phtml index 4892cceded8b7..d05faac66ffd1 100644 --- a/app/code/Magento/Theme/view/frontend/templates/html/print.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/html/print.phtml @@ -5,7 +5,14 @@ */ ?> diff --git a/app/code/Magento/Translation/Block/Html/Head/Config.php b/app/code/Magento/Translation/Block/Html/Head/Config.php index 4001929191072..1a1f2d6942cdf 100644 --- a/app/code/Magento/Translation/Block/Html/Head/Config.php +++ b/app/code/Magento/Translation/Block/Html/Head/Config.php @@ -31,7 +31,6 @@ class Config extends \Magento\Framework\View\Element\AbstractBlock /** * @param \Magento\Framework\View\Element\Context $context - * @param RequireJsConfig $config * @param \Magento\Framework\View\Page\Config $pageConfig * @param \Magento\Translation\Model\FileManager $fileManager * @param Inline $inline diff --git a/app/code/Magento/Translation/Model/Js/DataProvider.php b/app/code/Magento/Translation/Model/Js/DataProvider.php index 26b8e3e6615d3..0e0f0c9dd4808 100644 --- a/app/code/Magento/Translation/Model/Js/DataProvider.php +++ b/app/code/Magento/Translation/Model/Js/DataProvider.php @@ -1,6 +1,6 @@ config->getPatterns() as $pattern) { - $result = preg_match_all($pattern, $content, $matches); + $concatenatedContent = preg_replace('~(["\'])\s*?\+\s*?\1~', '', $content); + $result = preg_match_all($pattern, $concatenatedContent, $matches); if ($result) { if (isset($matches[2])) { foreach ($matches[2] as $match) { - $phrases[] = str_replace('\\\'', '\'', $match); + $phrases[] = str_replace(["\'", '\"'], ["'", '"'], $match); } } } diff --git a/app/code/Magento/Translation/composer.json b/app/code/Magento/Translation/composer.json index b776021b248cd..936a6e9dfef88 100644 --- a/app/code/Magento/Translation/composer.json +++ b/app/code/Magento/Translation/composer.json @@ -13,7 +13,7 @@ "magento/module-deploy": "100.1.*" }, "type": "magento2-module", - "version": "100.1.4", + "version": "100.1.5", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Translation/etc/di.xml b/app/code/Magento/Translation/etc/di.xml index ac9daaa2eca39..c75324029116b 100644 --- a/app/code/Magento/Translation/etc/di.xml +++ b/app/code/Magento/Translation/etc/di.xml @@ -59,8 +59,8 @@ - ~\$\.mage\.__\((?s)[^'"]*?(['"])(.+?)\1(?s).*?\)~ - ~\$t\((?s)[^'"]*?(["'])(.+?)\1(?s).*?\)~ + + diff --git a/app/code/Magento/Ui/Component/ExportButton.php b/app/code/Magento/Ui/Component/ExportButton.php index 9d5f125839003..20cc6623c847c 100644 --- a/app/code/Magento/Ui/Component/ExportButton.php +++ b/app/code/Magento/Ui/Component/ExportButton.php @@ -54,11 +54,13 @@ public function getComponentName() */ public function prepare() { + $context = $this->getContext(); $config = $this->getData('config'); if (isset($config['options'])) { $options = []; foreach ($config['options'] as $option) { - $option['url'] = $this->urlBuilder->getUrl($option['url']); + $additionalParams = $this->getAdditionalParams($config, $context); + $option['url'] = $this->urlBuilder->getUrl($option['url'], $additionalParams); $options[] = $option; } $config['options'] = $options; @@ -66,4 +68,25 @@ public function prepare() } parent::prepare(); } + + /** + * Get export button additional parameters + * + * @param array $config + * @param ContextInterface $context + * @return array + */ + private function getAdditionalParams($config, $context) + { + $additionalParams = []; + if (isset($config['additionalParams'])) { + foreach ($config['additionalParams'] as $paramName => $paramValue) { + if ('*' == $paramValue) { + $paramValue = $context->getRequestParam($paramName); + } + $additionalParams[$paramName] = $paramValue; + } + } + return $additionalParams; + } } diff --git a/app/code/Magento/Ui/Controller/Adminhtml/Export/GridToCsv.php b/app/code/Magento/Ui/Controller/Adminhtml/Export/GridToCsv.php index 13aed8fe300e5..759ec43ca2673 100644 --- a/app/code/Magento/Ui/Controller/Adminhtml/Export/GridToCsv.php +++ b/app/code/Magento/Ui/Controller/Adminhtml/Export/GridToCsv.php @@ -5,10 +5,13 @@ */ namespace Magento\Ui\Controller\Adminhtml\Export; +use Magento\Framework\App\ObjectManager; use Magento\Backend\App\Action; use Magento\Backend\App\Action\Context; use Magento\Ui\Model\Export\ConvertToCsv; use Magento\Framework\App\Response\Http\FileFactory; +use Magento\Ui\Component\MassAction\Filter; +use Psr\Log\LoggerInterface; /** * Class Render @@ -25,19 +28,37 @@ class GridToCsv extends Action */ protected $fileFactory; + /** + * @var Filter + */ + private $filter; + + /** + * @var LoggerInterface + */ + private $logger; + /** * @param Context $context * @param ConvertToCsv $converter * @param FileFactory $fileFactory + * @param Filter|null $filter + * @param LoggerInterface|null $logger */ public function __construct( Context $context, ConvertToCsv $converter, - FileFactory $fileFactory + FileFactory $fileFactory, + Filter $filter = null, + LoggerInterface $logger = null ) { parent::__construct($context); $this->converter = $converter; $this->fileFactory = $fileFactory; + $this->filter = $filter + ?: ObjectManager::getInstance()->get(Filter::class); + $this->logger = $logger + ?: ObjectManager::getInstance()->get(LoggerInterface::class); } /** @@ -48,6 +69,34 @@ public function __construct( */ public function execute() { - return $this->fileFactory->create('export.csv', $this->converter->getCsvFile(), 'var'); + return $this->fileFactory->create( + 'export.csv', + $this->converter->getCsvFile(), + 'var' + ); + } + + /** + * Checking if the user has access to requested component. + * + * @inheritDoc + */ + protected function _isAllowed() + { + if ($this->_request->getParam('namespace')) { + try { + $component = $this->filter->getComponent(); + $aclResource = $component->getData('acl'); + if ($aclResource) { + return $this->_authorization->isAllowed($aclResource); + } + } catch (\Exception $exception) { + $this->logger->critical($exception); + + return false; + } + } + + return true; } } diff --git a/app/code/Magento/Ui/Controller/Adminhtml/Export/GridToXml.php b/app/code/Magento/Ui/Controller/Adminhtml/Export/GridToXml.php index f00825a3e0bb9..da2609db91273 100644 --- a/app/code/Magento/Ui/Controller/Adminhtml/Export/GridToXml.php +++ b/app/code/Magento/Ui/Controller/Adminhtml/Export/GridToXml.php @@ -5,10 +5,13 @@ */ namespace Magento\Ui\Controller\Adminhtml\Export; +use Magento\Framework\App\ObjectManager; use Magento\Backend\App\Action; use Magento\Backend\App\Action\Context; use Magento\Ui\Model\Export\ConvertToXml; use Magento\Framework\App\Response\Http\FileFactory; +use Magento\Ui\Component\MassAction\Filter; +use Psr\Log\LoggerInterface; /** * Class Render @@ -25,19 +28,37 @@ class GridToXml extends Action */ protected $fileFactory; + /** + * @var Filter + */ + private $filter; + + /** + * @var LoggerInterface + */ + private $logger; + /** * @param Context $context * @param ConvertToXml $converter * @param FileFactory $fileFactory + * @param Filter|null $filter + * @param LoggerInterface|null $logger */ public function __construct( Context $context, ConvertToXml $converter, - FileFactory $fileFactory + FileFactory $fileFactory, + Filter $filter = null, + LoggerInterface $logger = null ) { parent::__construct($context); $this->converter = $converter; $this->fileFactory = $fileFactory; + $this->filter = $filter + ?: ObjectManager::getInstance()->get(Filter::class); + $this->logger = $logger + ?: ObjectManager::getInstance()->get(LoggerInterface::class); } /** @@ -48,6 +69,34 @@ public function __construct( */ public function execute() { - return $this->fileFactory->create('export.xml', $this->converter->getXmlFile(), 'var'); + return $this->fileFactory->create( + 'export.xml', + $this->converter->getXmlFile(), + 'var' + ); + } + + /** + * Checking if the user has access to requested component. + * + * @inheritDoc + */ + protected function _isAllowed() + { + if ($this->_request->getParam('namespace')) { + try { + $component = $this->filter->getComponent(); + $aclResource = $component->getData('acl'); + if ($aclResource) { + return $this->_authorization->isAllowed($aclResource); + } + } catch (\Exception $exception) { + $this->logger->critical($exception); + + return false; + } + } + + return true; } } diff --git a/app/code/Magento/Ui/Controller/Adminhtml/Index/Render.php b/app/code/Magento/Ui/Controller/Adminhtml/Index/Render.php index 85c8e3967be87..e16e3e43bdf30 100644 --- a/app/code/Magento/Ui/Controller/Adminhtml/Index/Render.php +++ b/app/code/Magento/Ui/Controller/Adminhtml/Index/Render.php @@ -37,6 +37,11 @@ public function execute() } $this->prepareComponent($component); + + if ($component->getContext()->getAcceptType() === 'json') { + $this->_response->setHeader('Content-Type', 'application/json'); + } + $this->_response->appendBody((string) $component->render()); } diff --git a/app/code/Magento/Ui/Model/Export/ConvertToCsv.php b/app/code/Magento/Ui/Model/Export/ConvertToCsv.php index 9eba829982533..e8136c7520054 100644 --- a/app/code/Magento/Ui/Model/Export/ConvertToCsv.php +++ b/app/code/Magento/Ui/Model/Export/ConvertToCsv.php @@ -8,7 +8,6 @@ use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Filesystem; -use Magento\Framework\Filesystem\Directory\WriteInterface; use Magento\Ui\Component\MassAction\Filter; /** @@ -17,7 +16,7 @@ class ConvertToCsv { /** - * @var WriteInterface + * @var DirectoryList */ protected $directory; diff --git a/app/code/Magento/Ui/Model/Export/ConvertToXml.php b/app/code/Magento/Ui/Model/Export/ConvertToXml.php index 58c3419e95312..8f06193740cfc 100644 --- a/app/code/Magento/Ui/Model/Export/ConvertToXml.php +++ b/app/code/Magento/Ui/Model/Export/ConvertToXml.php @@ -12,7 +12,6 @@ use Magento\Framework\Convert\ExcelFactory; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Filesystem; -use Magento\Framework\Filesystem\Directory\WriteInterface; use Magento\Ui\Component\MassAction\Filter; /** @@ -21,7 +20,7 @@ class ConvertToXml { /** - * @var WriteInterface + * @var DirectoryList */ protected $directory; diff --git a/app/code/Magento/Ui/TemplateEngine/Xhtml/Result.php b/app/code/Magento/Ui/TemplateEngine/Xhtml/Result.php index cda3106a14f49..e249a64861d43 100644 --- a/app/code/Magento/Ui/TemplateEngine/Xhtml/Result.php +++ b/app/code/Magento/Ui/TemplateEngine/Xhtml/Result.php @@ -80,7 +80,9 @@ public function getDocumentElement() */ public function appendLayoutConfiguration() { - $layoutConfiguration = $this->wrapContent(json_encode($this->structure->generate($this->component))); + $layoutConfiguration = $this->wrapContent( + json_encode($this->structure->generate($this->component), JSON_HEX_TAG) + ); $this->template->append($layoutConfiguration); } diff --git a/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/RenderTest.php b/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/RenderTest.php index 50476c0e41db4..090d54ebf721f 100644 --- a/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/RenderTest.php +++ b/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/RenderTest.php @@ -5,67 +5,71 @@ */ namespace Magento\Ui\Test\Unit\Controller\Adminhtml\Index; -use \Magento\Ui\Controller\Adminhtml\Index\Render; +use Magento\Ui\Controller\Adminhtml\Index\Render; +use PHPUnit_Framework_MockObject_MockObject as MockObject; /** - * Class RenderTest + * Unit test for Magento\Ui\Controller\Adminhtml\Index\Render */ class RenderTest extends \PHPUnit_Framework_TestCase { /** * @var Render */ - protected $render; + private $render; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var MockObject */ - protected $requestMock; + private $requestMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var MockObject */ - protected $responseMock; + private $responseMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\View\Element\UiComponentFactory|MockObject */ - protected $uiFactoryMock; + private $uiFactoryMock; /** - * @var \Magento\Backend\App\Action\Context|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Backend\App\Action\Context|MockObject */ private $contextMock; /** - * @var \Magento\Framework\AuthorizationInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\AuthorizationInterface|MockObject */ private $authorizationMock; /** - * @var \Magento\Backend\Model\Session|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Backend\Model\Session|MockObject */ private $sessionMock; /** - * @var \Magento\Framework\App\ActionFlag|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\App\ActionFlag|MockObject */ private $actionFlagMock; /** - * @var \Magento\Backend\Helper\Data|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Backend\Helper\Data|MockObject */ private $helperMock; + /** + * @inheritdoc + */ protected function setUp() { - $this->requestMock = $this->getMockBuilder('Magento\Framework\App\Request\Http') + $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) ->disableOriginalConstructor() ->getMock(); - $this->responseMock = $this->getMockBuilder('Magento\Framework\App\Response\Http') + $this->responseMock = $this->getMockBuilder(\Magento\Framework\App\Response\Http::class) ->disableOriginalConstructor() ->getMock(); - $this->contextMock = $this->getMockBuilder('Magento\Backend\App\Action\Context') + $this->contextMock = $this->getMockBuilder(\Magento\Backend\App\Action\Context::class) ->disableOriginalConstructor() ->getMock(); $this->uiFactoryMock = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponentFactory::class) @@ -110,38 +114,23 @@ public function testExecuteAjaxRequest() $name = 'test-name'; $renderedData = 'data'; - $this->requestMock->expects($this->any()) - ->method('getParam') - ->with('namespace') - ->willReturn($name); - $this->requestMock->expects($this->any()) - ->method('getParams') - ->willReturn([]); - $this->responseMock->expects($this->once()) - ->method('appendBody') - ->with($renderedData); + $this->prepareComponent($name, $renderedData); - /** - * @var \Magento\Framework\View\Element\UiComponentInterface|\PHPUnit_Framework_MockObject_MockObject $viewMock - */ - $viewMock = $this->getMockForAbstractClass( - 'Magento\Framework\View\Element\UiComponentInterface', - [], - '', - false, - true, - true, - ['render'] - ); - $viewMock->expects($this->once()) - ->method('render') - ->willReturn($renderedData); - $viewMock->expects($this->once()) - ->method('getChildComponents') - ->willReturn([]); - $this->uiFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($viewMock); + $this->responseMock->expects($this->never())->method('setHeader'); + + $this->render->executeAjaxRequest(); + } + + public function testExecuteAjaxJsonRequest() + { + $name = 'test-name'; + $renderedData = '{"data": "test"}'; + + $this->prepareComponent($name, $renderedData, 'json'); + + $this->responseMock->expects($this->once()) + ->method('setHeader') + ->with('Content-Type', 'application/json'); $this->render->executeAjaxRequest(); } @@ -160,9 +149,6 @@ public function testExecuteAjaxRequestWithoutPermissions($acl, $isAllowed) ->method('getParam') ->with('namespace') ->willReturn($name); - $this->requestMock->expects($this->any()) - ->method('getParams') - ->willReturn([]); $this->responseMock->expects($this->any()) ->method('appendBody') ->with($renderedData); @@ -180,6 +166,12 @@ public function testExecuteAjaxRequestWithoutPermissions($acl, $isAllowed) true, ['render'] ); + + $contextMock = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponent\ContextInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $contextMock->expects($this->any())->method('getAcceptType')->willReturn('html'); + $componentMock->expects($this->any()) ->method('render') ->willReturn($renderedData); @@ -190,6 +182,9 @@ public function testExecuteAjaxRequestWithoutPermissions($acl, $isAllowed) ->method('getData') ->with('acl') ->willReturn($acl); + $componentMock->expects($this->any()) + ->method('getContext') + ->willReturn($contextMock); $this->uiFactoryMock->expects($this->once()) ->method('create') ->willReturn($componentMock); @@ -208,4 +203,53 @@ public function executeAjaxRequestWithoutPermissionsDataProvider() ['', null], ]; } + + /** + * Prepares component mock. + * + * @param string $namespace + * @param string $renderedData + * @param string $acceptType + * @return \Magento\Framework\View\Element\UiComponentInterface|MockObject + */ + private function prepareComponent($namespace, $renderedData, $acceptType = 'html') + { + $this->requestMock->expects($this->any()) + ->method('getParam') + ->with('namespace') + ->willReturn($namespace); + $this->responseMock->expects($this->once()) + ->method('appendBody') + ->with($renderedData); + + /** @var \Magento\Framework\View\Element\UiComponentInterface|MockObject $componentMock */ + $componentMock = $this->getMockForAbstractClass( + \Magento\Framework\View\Element\UiComponentInterface::class, + [], + '', + false, + true, + true, + ['render'] + ); + $contextMock = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponent\ContextInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $contextMock->expects($this->once())->method('getAcceptType')->willReturn($acceptType); + + $componentMock->expects($this->once()) + ->method('render') + ->willReturn($renderedData); + $componentMock->expects($this->once()) + ->method('getChildComponents') + ->willReturn([]); + $componentMock->expects($this->once()) + ->method('getContext') + ->willReturn($contextMock); + $this->uiFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($componentMock); + + return $componentMock; + } } diff --git a/app/code/Magento/Ui/composer.json b/app/code/Magento/Ui/composer.json index 673edb6174190..c9bc0aa0d64ee 100644 --- a/app/code/Magento/Ui/composer.json +++ b/app/code/Magento/Ui/composer.json @@ -10,7 +10,7 @@ "magento/module-user": "100.1.*" }, "type": "magento2-module", - "version": "100.1.9", + "version": "100.1.11", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Ui/etc/di.xml b/app/code/Magento/Ui/etc/di.xml index bb29515777576..3b9803b72e26d 100644 --- a/app/code/Magento/Ui/etc/di.xml +++ b/app/code/Magento/Ui/etc/di.xml @@ -197,6 +197,7 @@ + Magento\Framework\Data\Argument\Interpreter\Constant configurableObjectArgumentInterpreterProxy configurableObjectArgumentInterpreterProxy arrayArgumentInterpreterProxy diff --git a/app/code/Magento/Ui/i18n/en_US.csv b/app/code/Magento/Ui/i18n/en_US.csv index f7f5b845ef8b6..109bebf1c836a 100644 --- a/app/code/Magento/Ui/i18n/en_US.csv +++ b/app/code/Magento/Ui/i18n/en_US.csv @@ -109,3 +109,25 @@ Ok,Ok Action,Action CSV,CSV "Excel XML","Excel XML" +"Please select one of the options above.","Please select one of the options above." +"Please select a file.","Please select a file." +"Please select one of the options.","Please select one of the options." +"Please enter a value less than or equal to %s.","Please enter a value less than or equal to %s." +"Please enter a value greater than or equal to %s.","Please enter a value greater than or equal to %s." +"Card type does not match credit card number.","Card type does not match credit card number." +"Credit card number does not match credit card type.","Credit card number does not match credit card type." +"Incorrect credit card expiration date.","Incorrect credit card expiration date." +"Please enter less or equal than %1 symbols.","Please enter less or equal than %1 symbols." +"Please enter more or equal than %1 symbols.","Please enter more or equal than %1 symbols." +"Please enter a valid value from list","Please enter a valid value from list" +"Please enter valid SKU key.","Please enter valid SKU key." +"Please enter a valid number.","Please enter a valid number." +"Admin is a required field in the each row.","Admin is a required field in the each row." +"Please fix this field.","Please fix this field." +"Please enter a valid date (ISO).","Please enter a valid date (ISO)." +"Please enter only digits.","Please enter only digits." +"Please enter the same value again.","Please enter the same value again." +"Please enter no more than {0} characters.","Please enter no more than {0} characters." +"Please enter at least {0} characters.","Please enter at least {0} characters." +"Please enter a value between {0} and {1} characters long.","Please enter a value between {0} and {1} characters long." +"Please enter a value between {0} and {1}.","Please enter a value between {0} and {1}." diff --git a/app/code/Magento/Ui/view/base/web/js/form/components/html.js b/app/code/Magento/Ui/view/base/web/js/form/components/html.js index 4a13c1ae7e641..67954b23ee821 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/components/html.js +++ b/app/code/Magento/Ui/view/base/web/js/form/components/html.js @@ -16,7 +16,10 @@ define([ loading: false, visible: true, template: 'ui/content/content', - additionalClasses: {} + additionalClasses: {}, + ignoreTmpls: { + content: true + } }, /** diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/abstract.js b/app/code/Magento/Ui/view/base/web/js/form/element/abstract.js index c07135b1f246a..a7f2fdbd7d090 100755 --- a/app/code/Magento/Ui/view/base/web/js/form/element/abstract.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/abstract.js @@ -205,7 +205,7 @@ define([ }, /** - * Sets 'value' as 'hidden' propertie's value, triggers 'toggle' event, + * Sets 'value' as 'hidden' property's value, triggers 'toggle' event, * sets instance's hidden identifier in params storage based on * 'value'. * diff --git a/app/code/Magento/Ui/view/base/web/js/form/form.js b/app/code/Magento/Ui/view/base/web/js/form/form.js index 81cae4910d58b..0114e0e7cb921 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/form.js +++ b/app/code/Magento/Ui/view/base/web/js/form/form.js @@ -38,7 +38,8 @@ define([ * @returns {Object} */ function collectData(items) { - var result = {}; + var result = {}, + name; items = Array.prototype.slice.call(items); @@ -54,6 +55,11 @@ define([ } break; + case 'select-multiple': + name = item.name.substring(0, item.name.length - 2); //remove [] from the name ending + result[name] = _.pluck(item.selectedOptions, 'value'); + break; + default: result[item.name] = item.value; } diff --git a/app/code/Magento/Ui/view/base/web/js/form/provider.js b/app/code/Magento/Ui/view/base/web/js/form/provider.js index a496d05d0d53c..3c40c75105e75 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/provider.js +++ b/app/code/Magento/Ui/view/base/web/js/form/provider.js @@ -17,6 +17,9 @@ define([ save: '${ $.submit_url }', beforeSave: '${ $.validate_url }' } + }, + ignoreTmpls: { + data: true } }, diff --git a/app/code/Magento/Ui/view/base/web/js/grid/provider.js b/app/code/Magento/Ui/view/base/web/js/grid/provider.js index 75bc13977e564..520f78e169fbb 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/provider.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/provider.js @@ -27,6 +27,9 @@ define([ listens: { params: 'onParamsChange', requestConfig: 'updateRequestConfig' + }, + ignoreTmpls: { + data: true } }, diff --git a/app/code/Magento/Ui/view/base/web/js/lib/core/class.js b/app/code/Magento/Ui/view/base/web/js/lib/core/class.js index aae3ca31bf803..5bfa87e650271 100644 --- a/app/code/Magento/Ui/view/base/web/js/lib/core/class.js +++ b/app/code/Magento/Ui/view/base/web/js/lib/core/class.js @@ -27,12 +27,12 @@ define([ * Creates constructor function which allows * initialization without usage of a 'new' operator. * - * @param {Object} protoProps - Prototypal propeties of a new consturctor. - * @param {Function} consturctor - * @returns {Function} Created consturctor. + * @param {Object} protoProps - Prototypal properties of a new constructor. + * @param {Function} constructor + * @returns {Function} Created constructor. */ - function createConstructor(protoProps, consturctor) { - var UiClass = consturctor; + function createConstructor(protoProps, constructor) { + var UiClass = constructor; if (!UiClass) { @@ -61,7 +61,7 @@ define([ Class = createConstructor({ /** - * Entry point to the initialization of consturctors' instance. + * Entry point to the initialization of constructors' instance. * * @param {Object} [options={}] * @returns {Class} Chainable. diff --git a/app/code/Magento/Ups/composer.json b/app/code/Magento/Ups/composer.json index 4ce3e2e20cc12..8f81ad73aa08c 100644 --- a/app/code/Magento/Ups/composer.json +++ b/app/code/Magento/Ups/composer.json @@ -13,7 +13,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.4", + "version": "100.1.5", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/UrlRewrite/composer.json b/app/code/Magento/UrlRewrite/composer.json index 639d60653e293..af0be1814df91 100644 --- a/app/code/Magento/UrlRewrite/composer.json +++ b/app/code/Magento/UrlRewrite/composer.json @@ -12,7 +12,7 @@ "magento/module-cms-url-rewrite": "100.1.*" }, "type": "magento2-module", - "version": "100.1.4", + "version": "100.1.5", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/User/Model/Backend/Config/ObserverConfig.php b/app/code/Magento/User/Model/Backend/Config/ObserverConfig.php index 29c4cc14ed674..e807749b11c32 100644 --- a/app/code/Magento/User/Model/Backend/Config/ObserverConfig.php +++ b/app/code/Magento/User/Model/Backend/Config/ObserverConfig.php @@ -72,7 +72,7 @@ public function getAdminPasswordLifetime() } /** - * Get admin maxiumum security failures from config + * Get admin maximum security failures from config * * @return int */ diff --git a/app/code/Magento/User/composer.json b/app/code/Magento/User/composer.json index 7d207ffbaf86d..e7e39cea332f0 100644 --- a/app/code/Magento/User/composer.json +++ b/app/code/Magento/User/composer.json @@ -12,7 +12,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.4", + "version": "100.1.5", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Usps/Model/Carrier.php b/app/code/Magento/Usps/Model/Carrier.php index 918990cc5a1a6..da08a110fb0b5 100644 --- a/app/code/Magento/Usps/Model/Carrier.php +++ b/app/code/Magento/Usps/Model/Carrier.php @@ -356,6 +356,15 @@ public function getResult() return $this->_result; } + /** + * @inheritdoc + * Starting from 23.02.2018 USPS doesn't allow to create free shipping labels via their API. + */ + public function isShippingLabelsAvailable() + { + return false; + } + /** * Get quotes * @@ -1414,6 +1423,8 @@ protected function _filterServiceName($name) * * @param \Magento\Framework\DataObject $request * @return string + * @deprecated This method should not be used anymore. + * @see \Magento\Usps\Model\Carrier::_doShipmentRequest method doc block. */ protected function _formUsExpressShipmentRequest(\Magento\Framework\DataObject $request) { @@ -1589,6 +1600,8 @@ protected function _convertPoundOunces($weightInPounds) * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @deprecated Should not be used anymore. + * @see \Magento\Usps\Model\Carrier::_doShipmentRequest doc block. */ protected function _formIntlShipmentRequest(\Magento\Framework\DataObject $request) { @@ -1842,6 +1855,8 @@ protected function _formIntlShipmentRequest(\Magento\Framework\DataObject $reque * @param \Magento\Framework\DataObject $request * @return \Magento\Framework\DataObject * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @deprecated This method must not be used anymore. Starting from 23.02.2018 USPS elimates API usage for + * free shipping labels generating. */ protected function _doShipmentRequest(\Magento\Framework\DataObject $request) { diff --git a/app/code/Magento/Usps/composer.json b/app/code/Magento/Usps/composer.json index c7226f5dfb3be..09fa8ed8b7445 100644 --- a/app/code/Magento/Usps/composer.json +++ b/app/code/Magento/Usps/composer.json @@ -15,7 +15,7 @@ "lib-libxml": "*" }, "type": "magento2-module", - "version": "100.1.4", + "version": "100.1.6", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Variable/Model/Variable.php b/app/code/Magento/Variable/Model/Variable.php index c96b4ab0720bc..dc06435576c32 100644 --- a/app/code/Magento/Variable/Model/Variable.php +++ b/app/code/Magento/Variable/Model/Variable.php @@ -61,7 +61,7 @@ public function __construct( protected function _construct() { parent::_construct(); - $this->_init('Magento\Variable\Model\ResourceModel\Variable'); + $this->_init(\Magento\Variable\Model\ResourceModel\Variable::class); } /** @@ -154,7 +154,7 @@ public function getVariablesOptionArray($withGroup = false) foreach ($collection->toOptionArray() as $variable) { $variables[] = [ 'value' => '{{customVar code=' . $variable['value'] . '}}', - 'label' => __('%1', $variable['label']), + 'label' => __('%1', $this->_escaper->escapeHtml($variable['label'])), ]; } if ($withGroup && $variables) { diff --git a/app/code/Magento/Variable/Test/Unit/Model/VariableTest.php b/app/code/Magento/Variable/Test/Unit/Model/VariableTest.php index 78d4570c9943e..bc99f4af6ad78 100644 --- a/app/code/Magento/Variable/Test/Unit/Model/VariableTest.php +++ b/app/code/Magento/Variable/Test/Unit/Model/VariableTest.php @@ -12,10 +12,10 @@ class VariableTest extends \PHPUnit_Framework_TestCase /** @var \Magento\Variable\Model\Variable */ private $model; - /** @var \PHPUnit_Framework_MockObject_MockObject */ + /** @var \PHPUnit_Framework_MockObject_MockObject */ private $escaperMock; - /** @var \PHPUnit_Framework_MockObject_MockObject */ + /** @var \PHPUnit_Framework_MockObject_MockObject */ private $resourceMock; /** @var \Magento\Framework\Phrase */ @@ -27,17 +27,17 @@ class VariableTest extends \PHPUnit_Framework_TestCase protected function setUp() { $this->objectManager = new ObjectManager($this); - $this->escaperMock = $this->getMockBuilder('Magento\Framework\Escaper') + $this->escaperMock = $this->getMockBuilder(\Magento\Framework\Escaper::class) ->disableOriginalConstructor() ->getMock(); - $this->resourceMock = $this->getMockBuilder('Magento\Variable\Model\ResourceModel\Variable') + $this->resourceMock = $this->getMockBuilder(\Magento\Variable\Model\ResourceModel\Variable::class) ->disableOriginalConstructor() ->getMock(); $this->model = $this->objectManager->getObject( - 'Magento\Variable\Model\Variable', + \Magento\Variable\Model\Variable::class, [ 'escaper' => $this->escaperMock, - 'resource' => $this->resourceMock + 'resource' => $this->resourceMock, ] ); $this->validationFailedPhrase = __('Validation has failed.'); @@ -99,63 +99,6 @@ public function testValidate($variableArray, $objectId, $expectedResult) $this->assertEquals($expectedResult, $this->model->validate($variableArray)); } - public function testGetVariablesOptionArrayNoGroup() - { - $origOptions = [ - ['value' => 'VAL', 'label' => 'LBL',] - ]; - - $transformedOptions = [ - ['value' => '{{customVar code=VAL}}', 'label' => __('%1', 'LBL')] - ]; - - $collectionMock = $this->getMockBuilder('\Magento\Variable\Model\ResourceModel\Variable\Collection') - ->disableOriginalConstructor() - ->getMock(); - $collectionMock->expects($this->any()) - ->method('toOptionArray') - ->willReturn($origOptions); - $mockVariable = $this->getMock( - 'Magento\Variable\Model\Variable', - ['getCollection'], - $this->objectManager->getConstructArguments('Magento\Variable\Model\Variable') - ); - $mockVariable->expects($this->any()) - ->method('getCollection') - ->willReturn($collectionMock); - $this->assertEquals($transformedOptions, $mockVariable->getVariablesOptionArray()); - } - - public function testGetVariablesOptionArrayWithGroup() - { - $origOptions = [ - ['value' => 'VAL', 'label' => 'LBL',] - ]; - - $transformedOptions = [ - 'label' => __('Custom Variables'), - 'value' => [ - ['value' => '{{customVar code=VAL}}', 'label' => __('%1', 'LBL')] - ] - ]; - - $collectionMock = $this->getMockBuilder('\Magento\Variable\Model\ResourceModel\Variable\Collection') - ->disableOriginalConstructor() - ->getMock(); - $collectionMock->expects($this->any()) - ->method('toOptionArray') - ->willReturn($origOptions); - $mockVariable = $this->getMock( - 'Magento\Variable\Model\Variable', - ['getCollection'], - $this->objectManager->getConstructArguments('Magento\Variable\Model\Variable') - ); - $mockVariable->expects($this->any()) - ->method('getCollection') - ->willReturn($collectionMock); - $this->assertEquals($transformedOptions, $mockVariable->getVariablesOptionArray(true)); - } - public function validateDataProvider() { $variable = [ diff --git a/app/code/Magento/Variable/composer.json b/app/code/Magento/Variable/composer.json index 63a4be3777299..fa5318c980c71 100644 --- a/app/code/Magento/Variable/composer.json +++ b/app/code/Magento/Variable/composer.json @@ -9,7 +9,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.2", + "version": "100.1.4", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Vault/composer.json b/app/code/Magento/Vault/composer.json index 3618ffda9f043..ad4be58226e51 100644 --- a/app/code/Magento/Vault/composer.json +++ b/app/code/Magento/Vault/composer.json @@ -13,7 +13,7 @@ "magento/module-theme": "100.1.*" }, "type": "magento2-module", - "version": "100.2.2", + "version": "100.2.3", "license": [ "proprietary" ], diff --git a/app/code/Magento/Version/Controller/Index/Index.php b/app/code/Magento/Version/Controller/Index/Index.php index 4314676c479f9..6e2c094e448c4 100644 --- a/app/code/Magento/Version/Controller/Index/Index.php +++ b/app/code/Magento/Version/Controller/Index/Index.php @@ -9,7 +9,6 @@ use Magento\Framework\App\Action\Action; use Magento\Framework\App\Action\Context; use Magento\Framework\App\ProductMetadataInterface; -use Magento\Framework\Exception\StateException; /** * Magento Version controller diff --git a/app/code/Magento/Version/composer.json b/app/code/Magento/Version/composer.json index bed6c5367eb80..00fa9a97d4b2c 100644 --- a/app/code/Magento/Version/composer.json +++ b/app/code/Magento/Version/composer.json @@ -6,7 +6,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.2", + "version": "100.1.3", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Webapi/composer.json b/app/code/Magento/Webapi/composer.json index b4726720cb731..f935fd12cee64 100644 --- a/app/code/Magento/Webapi/composer.json +++ b/app/code/Magento/Webapi/composer.json @@ -14,7 +14,7 @@ "magento/module-customer": "100.1.*" }, "type": "magento2-module", - "version": "100.1.5", + "version": "100.1.6", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/WebapiSecurity/composer.json b/app/code/Magento/WebapiSecurity/composer.json index a937fd11b9eb2..e99e5626b9246 100644 --- a/app/code/Magento/WebapiSecurity/composer.json +++ b/app/code/Magento/WebapiSecurity/composer.json @@ -7,7 +7,7 @@ "magento/framework": "100.1.*" }, "type": "magento2-module", - "version": "100.1.2", + "version": "100.1.3", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Weee/composer.json b/app/code/Magento/Weee/composer.json index 5e0b95168269f..24e694f1108fe 100644 --- a/app/code/Magento/Weee/composer.json +++ b/app/code/Magento/Weee/composer.json @@ -18,7 +18,7 @@ "magento/module-ui": "100.1.*" }, "type": "magento2-module", - "version": "100.1.2", + "version": "100.1.3", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/app/code/Magento/Widget/Model/Config/Converter.php b/app/code/Magento/Widget/Model/Config/Converter.php index 894d63ad4cc57..010c46da56950 100644 --- a/app/code/Magento/Widget/Model/Config/Converter.php +++ b/app/code/Magento/Widget/Model/Config/Converter.php @@ -44,7 +44,7 @@ public function convert($source) case 'parameters': /** @var $parameter \DOMNode */ foreach ($widgetSubNode->childNodes as $parameter) { - if ($parameter->nodeName === '#text') { + if ($parameter->nodeName === '#text' || $parameter->nodeName === '#comment') { continue; } $subNodeAttributes = $parameter->attributes; @@ -57,7 +57,7 @@ public function convert($source) $widgetArray['supported_containers'] = []; } foreach ($widgetSubNode->childNodes as $container) { - if ($container->nodeName === '#text') { + if ($container->nodeName === '#text' || $container->nodeName === '#comment') { continue; } $widgetArray['supported_containers'] = array_merge( diff --git a/app/code/Magento/Widget/Test/Unit/Model/_files/widget.xml b/app/code/Magento/Widget/Test/Unit/Model/_files/widget.xml index 0a3ace9463557..02e65707d322f 100644 --- a/app/code/Magento/Widget/Test/Unit/Model/_files/widget.xml +++ b/app/code/Magento/Widget/Test/Unit/Model/_files/widget.xml @@ -11,6 +11,7 @@ Orders and Returns Search Form + @@ -54,6 +55,7 @@ +