From cc2a1ea9b29610cf1d14f590ed5511e34e504eaa Mon Sep 17 00:00:00 2001 From: Gio <ggelashvili@gmail.com> Date: Wed, 24 May 2023 16:50:59 -0400 Subject: [PATCH 1/7] Makes Billable middleware useful for SPAs. If we are in SPA mode & the request is ajax it will respond with the proper redirect URL --- src/Http/Middleware/Billable.php | 39 +++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/Http/Middleware/Billable.php b/src/Http/Middleware/Billable.php index 9e3a1afa..671f3a86 100644 --- a/src/Http/Middleware/Billable.php +++ b/src/Http/Middleware/Billable.php @@ -27,23 +27,36 @@ class Billable */ public function handle(Request $request, Closure $next) { - if (Util::useNativeAppBridge() === false) { - throw new RuntimeException('You cannot use Billable middleware with SPA mode'); + if (Util::getShopifyConfig('billing_enabled') !== true) { + return $next($request); } - if (Util::getShopifyConfig('billing_enabled') === true) { - /** @var $shop IShopModel */ - $shop = auth()->user(); - if (!$shop->plan && !$shop->isFreemium() && !$shop->isGrandfathered()) { - // They're not grandfathered in, and there is no charge or charge was declined... redirect to billing - return Redirect::route( - Util::getShopifyConfig('route_names.billing'), - array_merge($request->input(), [ - 'shop' => $shop->getDomain()->toNative(), - 'host' => $request->get('host'), - ]) + // Proceed if we are on SPA mode & it's a non ajax request + if (! Util::useNativeAppBridge() && ! $request->ajax()) { + return $next($request); + } + + /** @var $shop IShopModel */ + $shop = auth()->user(); + + if (! $shop->plan && ! $shop->isFreemium() && ! $shop->isGrandfathered()) { + $args = [ + Util::getShopifyConfig('route_names.billing'), + array_merge($request->input(), [ + 'shop' => $shop->getDomain()->toNative(), + 'host' => $request->get('host'), + ]), + ]; + + if ($request->ajax()) { + return response()->json( + ['forceRedirectUrl' => route(...$args)], + 403 ); } + + // They're not grandfathered in, and there is no charge or charge was declined... redirect to billing + return Redirect::route(...$args); } // Move on, everything's fine From 041844b7ab3de26428b3e960e636a78e418a2c3d Mon Sep 17 00:00:00 2001 From: Gio <ggelashvili@gmail.com> Date: Thu, 25 May 2023 14:40:32 -0400 Subject: [PATCH 2/7] Removes unused use statement --- src/Http/Middleware/Billable.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Http/Middleware/Billable.php b/src/Http/Middleware/Billable.php index 671f3a86..08f1d4e3 100644 --- a/src/Http/Middleware/Billable.php +++ b/src/Http/Middleware/Billable.php @@ -8,7 +8,6 @@ use Illuminate\Support\Facades\Redirect; use Osiset\ShopifyApp\Contracts\ShopModel as IShopModel; use Osiset\ShopifyApp\Util; -use RuntimeException; /** * Responsible for ensuring the shop is being billed. From 3e9667ff9bb1ff6a706fad4d3acf74f8972bdb6c Mon Sep 17 00:00:00 2001 From: Gio <ggelashvili@gmail.com> Date: Mon, 29 May 2023 19:11:11 -0400 Subject: [PATCH 3/7] Improves readability & adds check for when user/shop is null --- src/Http/Middleware/Billable.php | 43 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/Http/Middleware/Billable.php b/src/Http/Middleware/Billable.php index 08f1d4e3..90924dd8 100644 --- a/src/Http/Middleware/Billable.php +++ b/src/Http/Middleware/Billable.php @@ -18,11 +18,11 @@ class Billable * Checks if a shop has paid for access. * * @param Request $request The request object. - * @param Closure $next The next action. - * - *@throws Exception + * @param Closure $next The next action. * * @return mixed + * @throws Exception + * */ public function handle(Request $request, Closure $next) { @@ -38,27 +38,26 @@ public function handle(Request $request, Closure $next) /** @var $shop IShopModel */ $shop = auth()->user(); - if (! $shop->plan && ! $shop->isFreemium() && ! $shop->isGrandfathered()) { - $args = [ - Util::getShopifyConfig('route_names.billing'), - array_merge($request->input(), [ - 'shop' => $shop->getDomain()->toNative(), - 'host' => $request->get('host'), - ]), - ]; - - if ($request->ajax()) { - return response()->json( - ['forceRedirectUrl' => route(...$args)], - 403 - ); - } + // if shop has plan or is on freemium or is grandfathered then move on with request + if (! $shop || $shop->plan || $shop->isFreemium() || $shop->isGrandfathered()) { + return $next($request); + } - // They're not grandfathered in, and there is no charge or charge was declined... redirect to billing - return Redirect::route(...$args); + $args = [ + Util::getShopifyConfig('route_names.billing'), + array_merge($request->input(), [ + 'shop' => $shop->getDomain()->toNative(), + 'host' => $request->get('host'), + ]), + ]; + + if ($request->ajax()) { + return response()->json( + ['forceRedirectUrl' => route(...$args)], + 403 + ); } - // Move on, everything's fine - return $next($request); + return Redirect::route(...$args); } } From c62ea4510e7f48de0dbd25301ea8f2066616cc11 Mon Sep 17 00:00:00 2001 From: Gio <ggelashvili@gmail.com> Date: Thu, 1 Jun 2023 15:49:19 -0400 Subject: [PATCH 4/7] Fixes code style --- src/Http/Middleware/Billable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Middleware/Billable.php b/src/Http/Middleware/Billable.php index 90924dd8..dc2ab4b5 100644 --- a/src/Http/Middleware/Billable.php +++ b/src/Http/Middleware/Billable.php @@ -20,9 +20,9 @@ class Billable * @param Request $request The request object. * @param Closure $next The next action. * - * @return mixed * @throws Exception * + * @return mixed */ public function handle(Request $request, Closure $next) { From f650925f7f29c3c0bf3b4a4ccdc17ab5d4f0ceec Mon Sep 17 00:00:00 2001 From: Gio <ggelashvili@gmail.com> Date: Thu, 22 Jun 2023 12:44:57 -0400 Subject: [PATCH 5/7] Adds test cases --- tests/Http/Middleware/BillableTest.php | 46 ++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/Http/Middleware/BillableTest.php b/tests/Http/Middleware/BillableTest.php index ff3de70b..6f81c4dd 100644 --- a/tests/Http/Middleware/BillableTest.php +++ b/tests/Http/Middleware/BillableTest.php @@ -8,6 +8,7 @@ use Osiset\ShopifyApp\Storage\Models\Plan; use Osiset\ShopifyApp\Test\TestCase; use Osiset\ShopifyApp\Util; +use Illuminate\Http\Request; class BillableTest extends TestCase { @@ -100,4 +101,49 @@ public function testDisabledBillingShouldPassOn(): void $this->assertTrue($result[0]); } + + public function testNoNativeAppBridgeAndNoAjaxRequest(): void + { + $plan = factory(Util::getShopifyConfig('models.plan', Plan::class))->states('type_recurring')->create(); + $shop = factory($this->model)->create(['plan_id' => $plan->getId()->toNative()]); + + factory(Util::getShopifyConfig('models.charge', Charge::class))->states('type_recurring')->create( + [ + 'plan_id' => $plan->getId()->toNative(), + 'user_id' => $shop->getId()->toNative(), + ] + ); + + $this->auth->login($shop); + $this->app['config']->set('shopify-app.billing_enabled', true); + $this->app['config']->set('shopify-app.frontend_engine', 'REACT'); + + $request = Request::create('/test', 'GET'); + + $this->assertFalse($request->ajax()); + + $result = $this->runMiddleware(BillableMiddleware::class, $request); + + $this->assertTrue($result[0]); + } + + public function testAjaxRequest(): void + { + $shop = factory($this->model)->create(); + + $this->auth->login($shop); + $this->app['config']->set('shopify-app.billing_enabled', true); + $this->app['config']->set('shopify-app.frontend_engine', 'REACT'); + + $request = Request::create('/test', 'GET'); + $request->headers->set('X-Requested-With', 'XMLHttpRequest'); + + $this->assertTrue($request->ajax()); + + $response = $this->runMiddleware(BillableMiddleware::class, $request); + + $this->assertFalse($response[0]); + $this->assertEquals(403, $response[1]->getStatusCode()); + $this->assertArrayHasKey('forceRedirectUrl', $response[1]->getData(true)); + } } From 05ae0412eefa8c837af8b67bd03191da482f5b22 Mon Sep 17 00:00:00 2001 From: Gio <ggelashvili@gmail.com> Date: Thu, 22 Jun 2023 13:28:06 -0400 Subject: [PATCH 6/7] WIP --- tests/Http/Middleware/BillableTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Http/Middleware/BillableTest.php b/tests/Http/Middleware/BillableTest.php index 6f81c4dd..ffb71f9a 100644 --- a/tests/Http/Middleware/BillableTest.php +++ b/tests/Http/Middleware/BillableTest.php @@ -3,12 +3,12 @@ namespace Osiset\ShopifyApp\Test\Http\Middleware; use Illuminate\Auth\AuthManager; +use Illuminate\Http\Request; use Osiset\ShopifyApp\Http\Middleware\Billable as BillableMiddleware; use Osiset\ShopifyApp\Storage\Models\Charge; use Osiset\ShopifyApp\Storage\Models\Plan; use Osiset\ShopifyApp\Test\TestCase; use Osiset\ShopifyApp\Util; -use Illuminate\Http\Request; class BillableTest extends TestCase { From c9b80479e1e7e01e57da637573b9d5357d18ecc1 Mon Sep 17 00:00:00 2001 From: Gio <ggelashvili@gmail.com> Date: Wed, 12 Jul 2023 18:01:38 -0400 Subject: [PATCH 7/7] WIP --- src/Http/Middleware/Billable.php | 2 +- tests/Http/Middleware/BillableTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Http/Middleware/Billable.php b/src/Http/Middleware/Billable.php index dc2ab4b5..20479ab5 100644 --- a/src/Http/Middleware/Billable.php +++ b/src/Http/Middleware/Billable.php @@ -54,7 +54,7 @@ public function handle(Request $request, Closure $next) if ($request->ajax()) { return response()->json( ['forceRedirectUrl' => route(...$args)], - 403 + 402 ); } diff --git a/tests/Http/Middleware/BillableTest.php b/tests/Http/Middleware/BillableTest.php index ffb71f9a..5c1d1978 100644 --- a/tests/Http/Middleware/BillableTest.php +++ b/tests/Http/Middleware/BillableTest.php @@ -143,7 +143,7 @@ public function testAjaxRequest(): void $response = $this->runMiddleware(BillableMiddleware::class, $request); $this->assertFalse($response[0]); - $this->assertEquals(403, $response[1]->getStatusCode()); + $this->assertEquals(402, $response[1]->getStatusCode()); $this->assertArrayHasKey('forceRedirectUrl', $response[1]->getData(true)); } }