diff --git a/src/Http/Middleware/Billable.php b/src/Http/Middleware/Billable.php index 9e3a1afa..20479ab5 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. @@ -19,34 +18,46 @@ class Billable * Checks if a shop has paid for access. * * @param Request $request The request object. - * @param Closure $next The next action. + * @param Closure $next The next action. * - *@throws Exception + * @throws Exception * * @return mixed */ 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); } - // Move on, everything's fine - return $next($request); + /** @var $shop IShopModel */ + $shop = auth()->user(); + + // 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); + } + + $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)], + 402 + ); + } + + return Redirect::route(...$args); } } diff --git a/tests/Http/Middleware/BillableTest.php b/tests/Http/Middleware/BillableTest.php index ff3de70b..5c1d1978 100644 --- a/tests/Http/Middleware/BillableTest.php +++ b/tests/Http/Middleware/BillableTest.php @@ -3,6 +3,7 @@ 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; @@ -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(402, $response[1]->getStatusCode()); + $this->assertArrayHasKey('forceRedirectUrl', $response[1]->getData(true)); + } }