Skip to content
This repository has been archived by the owner on Nov 30, 2022. It is now read-only.

Commit

Permalink
Feature/cookieless - Billing, Turbo (#772)
Browse files Browse the repository at this point in the history
* add turbo support

* change name for test package

* add get token helper

* add missing auth url exception

* added billing to allowed routes, change token receipt

* exception added to prevent loop redirects if authorization link is empty

* added billing payments with tokens

* change middleware

* return name

* remove session helper

* add shop domain to request

* turbolinks auth token to header

* usage charge billing

* remove shopQuery

* remove unused classes

* change middleware
  • Loading branch information
Vitaly authored May 5, 2021
1 parent 8ac298f commit f0febc8
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 50 deletions.
1 change: 1 addition & 0 deletions src/ShopifyApp/Actions/AuthenticateShop.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ public function __invoke(Request $request): array
ShopDomain::fromNative($request->get('shop')),
$request->query('code')
);

if (! $result['completed']) {
// No code, redirect to auth URL
return [$result, false];
Expand Down
10 changes: 10 additions & 0 deletions src/ShopifyApp/Exceptions/MissingAuthUrlException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Osiset\ShopifyApp\Exceptions;

/**
* Exception for handling a missing shop's myshopify domain.
*/
class MissingAuthUrlException extends BaseException
{
}
21 changes: 1 addition & 20 deletions src/ShopifyApp/Http/Middleware/Billable.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,6 @@
*/
class Billable
{
/**
* The shop session helper.
*
* @var ShopSession
*/
protected $shopSession;

/**
* Setup.
*
* @param ShopSession $shopSession The shop session helper.
*
* @return void
*/
public function __construct(ShopSession $shopSession)
{
$this->shopSession = $shopSession;
}

/**
* Checks if a shop has paid for access.
*
Expand All @@ -43,7 +24,7 @@ public function __construct(ShopSession $shopSession)
public function handle(Request $request, Closure $next)
{
if (getShopifyConfig('billing_enabled') === true) {
$shop = $this->shopSession->getShop();
$shop = auth()->user();
if (! $shop->isFreemium() && ! $shop->isGrandfathered() && ! $shop->plan) {
// They're not grandfathered in, and there is no charge or charge was declined... redirect to billing
return Redirect::route(getShopifyConfig('route_names.billing'), $request->input());
Expand Down
9 changes: 5 additions & 4 deletions src/ShopifyApp/Http/Middleware/VerifyShopify.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Osiset\ShopifyApp\Objects\Values\NullShopDomain;
use Osiset\ShopifyApp\Objects\Values\NullableSessionId;
use Osiset\ShopifyApp\Contracts\ApiHelper as IApiHelper;
use function Osiset\ShopifyApp\getAccessTokenFromRequest;
use Osiset\ShopifyApp\Contracts\Queries\Shop as IShopQuery;
use Osiset\ShopifyApp\Exceptions\SignatureVerificationException;
use Osiset\ShopifyApp\Contracts\Objects\Values\ShopDomain as ShopDomainValue;
Expand Down Expand Up @@ -104,13 +105,13 @@ public function handle(Request $request, Closure $next)
throw new SignatureVerificationException('Unable to verify signature.');
}

// Continue if current route is an auth route
if (Str::startsWith($request->getRequestUri(), '/authenticate')) {
// Continue if current route is an auth or billing route
if (Str::startsWith($request->getRequestUri(), ['/authenticate', '/billing'])) {
return $next($request);
}

// Get the token (if available)
$tokenSource = $request->ajax() ? $request->bearerToken() : $request->get('token');
$tokenSource = getAccessTokenFromRequest($request);

if ($tokenSource === null) {
// Not available, we need to get one
return $this->handleMissingToken($request);
Expand Down
6 changes: 5 additions & 1 deletion src/ShopifyApp/Traits/AuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
use Osiset\ShopifyApp\Actions\AuthenticateShop;
use Osiset\ShopifyApp\Exceptions\MissingAuthUrlException;
use Osiset\ShopifyApp\Exceptions\SignatureVerificationException;
use function Osiset\ShopifyApp\getShopifyConfig;
use Osiset\ShopifyApp\Objects\Values\ShopDomain;
Expand All @@ -29,11 +30,14 @@ public function authenticate(Request $request, AuthenticateShop $authShop)

// Run the action
[$result, $status] = $authShop($request);

if ($status === null) {
// Show exception, something is wrong
throw new SignatureVerificationException('Invalid HMAC verification');
} elseif ($status === false) {
// No code, redirect to auth URL
if (!$result['url']) {
throw new MissingAuthUrlException('Missing auth url');
}
return View::make(
'shopify-app::auth.fullpage_redirect',
[
Expand Down
40 changes: 20 additions & 20 deletions src/ShopifyApp/Traits/BillingController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@

namespace Osiset\ShopifyApp\Traits;

use Illuminate\Contracts\View\View as ViewView;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
use Osiset\ShopifyApp\Actions\ActivatePlan;
use Osiset\ShopifyApp\Actions\ActivateUsageCharge;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Redirect;
use Osiset\ShopifyApp\Actions\GetPlanUrl;
use Osiset\ShopifyApp\Actions\ActivatePlan;
use Osiset\ShopifyApp\Objects\Values\PlanId;
use Illuminate\Contracts\View\View as ViewView;
use function Osiset\ShopifyApp\getShopifyConfig;
use Osiset\ShopifyApp\Actions\ActivateUsageCharge;
use Osiset\ShopifyApp\Objects\Values\NullablePlanId;
use Osiset\ShopifyApp\Http\Requests\StoreUsageCharge;
use Osiset\ShopifyApp\Objects\Transfers\UsageChargeDetails as UsageChargeDetailsTransfer;
use Osiset\ShopifyApp\Objects\Values\ChargeReference;
use Osiset\ShopifyApp\Objects\Values\NullablePlanId;
use Osiset\ShopifyApp\Objects\Values\PlanId;
use Osiset\ShopifyApp\Services\ShopSession;
use Osiset\ShopifyApp\Objects\Transfers\UsageChargeDetails as UsageChargeDetailsTransfer;

/**
* Responsible for billing a shop for plans and usage charges.
Expand All @@ -28,15 +27,16 @@ trait BillingController
*
* @param int|null $plan The plan's ID, if provided in route.
* @param GetPlanUrl $getPlanUrl The action for getting the plan URL.
* @param ShopSession $shopSession The shop session helper.
*
* @return ViewView
*/
public function index(?int $plan = null, GetPlanUrl $getPlanUrl, ShopSession $shopSession): ViewView
public function index(?int $plan = null, GetPlanUrl $getPlanUrl): ViewView
{
$shop = auth()->user();

// Get the plan URL for redirect
$url = $getPlanUrl(
$shopSession->getShop()->getId(),
$shop->getId(),
NullablePlanId::fromNative($plan)
);

Expand All @@ -53,25 +53,26 @@ public function index(?int $plan = null, GetPlanUrl $getPlanUrl, ShopSession $sh
* @param int $plan The plan's ID.
* @param Request $request The HTTP request object.
* @param ActivatePlan $activatePlan The action for activating the plan for a shop.
* @param ShopSession $shopSession The shop session helper.
*
* @return RedirectResponse
*/
public function process(
int $plan,
Request $request,
ActivatePlan $activatePlan,
ShopSession $shopSession
ActivatePlan $activatePlan
): RedirectResponse {

// Activate the plan and save
$result = $activatePlan(
$shopSession->getShop()->getId(),
$request->user()->getId(),
PlanId::fromNative($plan),
ChargeReference::fromNative((int) $request->query('charge_id'))
);

// Go to homepage of app
return Redirect::route(getShopifyConfig('route_names.home'))->with(
return Redirect::route(getShopifyConfig('route_names.home'), [
'shop' => $request->user()->getDomain()->toNative()
])->with(
$result ? 'success' : 'failure',
'billing'
);
Expand All @@ -88,8 +89,7 @@ public function process(
*/
public function usageCharge(
StoreUsageCharge $request,
ActivateUsageCharge $activateUsageCharge,
ShopSession $shopSession
ActivateUsageCharge $activateUsageCharge
): RedirectResponse {
$validated = $request->validated();

Expand All @@ -100,7 +100,7 @@ public function usageCharge(

// Activate and save the usage charge
$activateUsageCharge(
$shopSession->getShop()->getId(),
$request->user()->getId(),
$ucd
);

Expand Down
22 changes: 20 additions & 2 deletions src/ShopifyApp/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

namespace Osiset\ShopifyApp;

use LogicException;
use Illuminate\Support\Str;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Str;
use LogicException;
use Osiset\ShopifyApp\Contracts\ShopModel;
use Illuminate\Http\Request as HttpRequest;

/**
* HMAC creation helper.
Expand Down Expand Up @@ -210,3 +211,20 @@ function tokenUrl(string $url, ?ShopModel $shop = null): string

return "{$url}{$sep}token={$token}";
}


/**
* Get the token (if available)
*
* @param Request $request The request object.
*
* @return string
*/
function getAccessTokenFromRequest(HttpRequest $request): ?string
{
if (getShopifyConfig('turbo_enabled')) {
return $request->bearerToken() ?? $request->get('token');
}

return $request->ajax() ? $request->bearerToken() : $request->get('token');
}
10 changes: 10 additions & 0 deletions src/ShopifyApp/resources/config/shopify-app.php
Original file line number Diff line number Diff line change
Expand Up @@ -383,4 +383,14 @@
*/

'config_api_callback' => null,

/*
|--------------------------------------------------------------------------
| Enable Turbolinks or Hotwire Turbo
|--------------------------------------------------------------------------
|
| If you use Turbolinks / Turbo And Livewire turn on this setting to get the token
|
*/
'turbo_enabled' => false,
];
6 changes: 3 additions & 3 deletions src/ShopifyApp/resources/routes/shopify.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
'/billing/{plan?}',
'Osiset\ShopifyApp\Http\Controllers\BillingController@index'
)
->middleware(['auth.shopify'])
->middleware(['verify.shopify'])
->where('plan', '^([0-9]+|)$')
->name(getShopifyConfig('route_names.billing'));
}
Expand All @@ -111,7 +111,7 @@
'/billing/process/{plan?}',
'Osiset\ShopifyApp\Http\Controllers\BillingController@process'
)
->middleware(['auth.shopify'])
->middleware(['verify.shopify'])
->where('plan', '^([0-9]+|)$')
->name(getShopifyConfig('route_names.billing.process'));
}
Expand All @@ -131,7 +131,7 @@
'/billing/usage-charge',
'Osiset\ShopifyApp\Http\Controllers\BillingController@usageCharge'
)
->middleware(['auth.shopify'])
->middleware(['verify.shopify'])
->name(getShopifyConfig('route_names.billing.usage_charge'));
}
});
13 changes: 13 additions & 0 deletions src/ShopifyApp/resources/views/layouts/default.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@
forceRedirect: true,
});
</script>
@if(\Osiset\ShopifyApp\getShopifyConfig('turbo_enabled'))
<script>
document.addEventListener("turbolinks:request-start", (event) => {
utils.getSessionToken(app).then((token) => {
let xhr = event.data.xhr;
xhr.open('GET', event.data.url, true);
xhr.setRequestHeader("Authorization", "Bearer " + token);
xhr.send();
});
});
</script>
@endif

@include('shopify-app::partials.flash_messages')
@endif
Expand Down

0 comments on commit f0febc8

Please sign in to comment.