From 8587f050e96f8adac55951a58fe87b363bec1cce Mon Sep 17 00:00:00 2001
From: Ere Maijala <ere.maijala@helsinki.fi>
Date: Tue, 3 Jan 2017 22:51:36 +0200
Subject: [PATCH] Use correct cookie path for cart. (#876)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- Otherwise server-side functionality such as emptying the cart won’t work since it will push the cookie using a path while the JS functionality uses a path-less cookie.
---
 module/VuFind/src/VuFind/Cart.php             | 10 +++++++
 .../src/VuFindTest/Mink/CartTest.php          | 28 +++++++++++++++++++
 themes/bootstrap3/js/cart.js                  | 18 ++++++++----
 .../bootstrap3/templates/layout/layout.phtml  |  6 ++++
 4 files changed, 56 insertions(+), 6 deletions(-)

diff --git a/module/VuFind/src/VuFind/Cart.php b/module/VuFind/src/VuFind/Cart.php
index 3c4a06d8509..3195c10216d 100644
--- a/module/VuFind/src/VuFind/Cart.php
+++ b/module/VuFind/src/VuFind/Cart.php
@@ -306,6 +306,16 @@ class Cart
         return $this->cookieManager->getDomain();
     }
 
+    /**
+     * Get cookie path ('/' if unset).
+     *
+     * @return string
+     */
+    public function getCookiePath()
+    {
+        return $this->cookieManager->getPath();
+    }
+
     /**
      * Process parameters and return the cart content.
      *
diff --git a/module/VuFind/tests/integration-tests/src/VuFindTest/Mink/CartTest.php b/module/VuFind/tests/integration-tests/src/VuFindTest/Mink/CartTest.php
index b764b190676..d08ce405628 100644
--- a/module/VuFind/tests/integration-tests/src/VuFindTest/Mink/CartTest.php
+++ b/module/VuFind/tests/integration-tests/src/VuFindTest/Mink/CartTest.php
@@ -427,6 +427,34 @@ class CartTest extends \VuFindTest\Unit\MinkTestCase
         $this->assertEquals('0', $this->findCss($page, '#cartItems strong')->getText());
     }
 
+    /**
+     * Test that we can put items in the cart and then remove them outside of
+     * the lightbox.
+     *
+     * @return void
+     */
+    public function testFillAndEmptyCartWithoutLightbox()
+    {
+        // Turn on limit by path setting; there used to be a bug where cookie
+        // paths were set inconsistently between JS and server-side code. This
+        // test should catch any regressions in that area.
+        $page = $this->setUpGenericCartTest(
+            ['config' => ['Cookies' => ['limit_by_path' => 1]]]
+        );
+
+        // Go to the cart page and activate the "empty" control:
+        $session = $this->getMinkSession();
+        $session->visit($this->getVuFindUrl() . '/Cart');
+        $empty = $this->findCss($page, '#cart-empty-label');
+        $empty->click();
+        $emptyConfirm = $this->findCss($page, '#cart-confirm-empty');
+        $emptyConfirm->click();
+
+        // Confirm that the cart has truly been emptied:
+        $this->snooze(); // wait for display to update
+        $this->assertEquals('0', $this->findCss($page, '#cartItems strong')->getText());
+    }
+
     /**
      * Test that the email control works.
      *
diff --git a/themes/bootstrap3/js/cart.js b/themes/bootstrap3/js/cart.js
index 3d2474241b6..15cd6201d10 100644
--- a/themes/bootstrap3/js/cart.js
+++ b/themes/bootstrap3/js/cart.js
@@ -6,11 +6,16 @@ VuFind.register('cart', function Cart() {
   var _COOKIE_SOURCES = 'vufind_cart_src';
   var _COOKIE_DELIM = "\t";
   var _COOKIE_DOMAIN = false;
+  var _COOKIE_PATH = '/';
 
   function setDomain(domain) {
     _COOKIE_DOMAIN = domain;
   }
 
+  function setCookiePath(path) {
+    _COOKIE_PATH = path;
+  }
+
   function _uniqueArray(op) {
     var ret = [];
     for (var i = 0; i < op.length; i++) {
@@ -70,11 +75,11 @@ VuFind.register('cart', function Cart() {
       // Add source to source cookie
       cartItems[cartItems.length] = String.fromCharCode(65 + cartSources.length) + id;
       cartSources[cartSources.length] = source;
-      Cookies.setItem(_COOKIE_SOURCES, cartSources.join(_COOKIE_DELIM), false, '/', _COOKIE_DOMAIN);
+      Cookies.setItem(_COOKIE_SOURCES, cartSources.join(_COOKIE_DELIM), false, _COOKIE_PATH, _COOKIE_DOMAIN);
     } else {
       cartItems[cartItems.length] = String.fromCharCode(65 + sIndex) + id;
     }
-    Cookies.setItem(_COOKIE, _uniqueArray(cartItems).join(_COOKIE_DELIM), false, '/', _COOKIE_DOMAIN);
+    Cookies.setItem(_COOKIE, _uniqueArray(cartItems).join(_COOKIE_DELIM), false, _COOKIE_PATH, _COOKIE_DOMAIN);
     updateCount();
     return true;
   }
@@ -109,11 +114,11 @@ VuFind.register('cart', function Cart() {
         }
       }
       if (cartItems.length > 0) {
-        Cookies.setItem(_COOKIE, _uniqueArray(cartItems).join(_COOKIE_DELIM), false, '/', _COOKIE_DOMAIN);
-        Cookies.setItem(_COOKIE_SOURCES, _uniqueArray(cartSources).join(_COOKIE_DELIM), false, '/', _COOKIE_DOMAIN);
+        Cookies.setItem(_COOKIE, _uniqueArray(cartItems).join(_COOKIE_DELIM), false, _COOKIE_PATH, _COOKIE_DOMAIN);
+        Cookies.setItem(_COOKIE_SOURCES, _uniqueArray(cartSources).join(_COOKIE_DELIM), false, _COOKIE_PATH, _COOKIE_DOMAIN);
       } else {
-        Cookies.removeItem(_COOKIE, '/', _COOKIE_DOMAIN);
-        Cookies.removeItem(_COOKIE_SOURCES, '/', _COOKIE_DOMAIN);
+        Cookies.removeItem(_COOKIE, _COOKIE_PATH, _COOKIE_DOMAIN);
+        Cookies.removeItem(_COOKIE_SOURCES, _COOKIE_PATH, _COOKIE_DOMAIN);
       }
       updateCount();
       return true;
@@ -211,6 +216,7 @@ VuFind.register('cart', function Cart() {
     getFullItems: getFullItems,
     updateCount: updateCount,
     setDomain: setDomain,
+    setCookiePath: setCookiePath,
     // Init
     init: init
   };
diff --git a/themes/bootstrap3/templates/layout/layout.phtml b/themes/bootstrap3/templates/layout/layout.phtml
index e42f5ceaa91..fd89ef37d49 100644
--- a/themes/bootstrap3/templates/layout/layout.phtml
+++ b/themes/bootstrap3/templates/layout/layout.phtml
@@ -75,6 +75,12 @@
               'VuFind.cart.setDomain("' . $domain . '");'
             );
           }
+          $cookiePath = $cart->getCookiePath();
+          if (!empty($cookiePath)) {
+            $this->headScript()->appendScript(
+              'VuFind.cart.setCookiePath("' . $cookiePath . '");'
+            );
+          }
           $this->jsTranslations()->addStrings(
             [
               'addBookBag' => 'Add to Book Bag',
-- 
GitLab