the browser-facing portion of osu!
at master 4.3 kB view raw
1<?php 2 3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4// See the LICENCE file in the repository root for full licence text. 5 6namespace App\Http\Controllers\Payments; 7 8use App\Exceptions\InvalidSignatureException; 9use App\Exceptions\Store\OrderException; 10use App\Libraries\OrderCheckout; 11use App\Libraries\Payments\XsollaPaymentProcessor; 12use App\Libraries\Payments\XsollaSignature; 13use App\Libraries\Payments\XsollaUserNotFoundException; 14use App\Models\Store\Order; 15use Auth; 16use Exception; 17use Illuminate\Http\Request as HttpRequest; 18use Request; 19use Xsolla\SDK\API\PaymentUI\TokenRequest; 20use Xsolla\SDK\API\XsollaClient; 21 22class XsollaController extends Controller 23{ 24 public function __construct() 25 { 26 $this->middleware('auth', ['except' => ['callback']]); 27 $this->middleware('check-user-restricted', ['except' => ['callback']]); 28 $this->middleware('verify-user', ['except' => ['callback']]); 29 30 parent::__construct(); 31 } 32 33 public function token() 34 { 35 $projectId = $GLOBALS['cfg']['payments']['xsolla']['project_id']; 36 $user = Auth::user(); 37 $order = Order::whereOrderNumber(request('orderNumber')) 38 ->whereCanCheckout() 39 ->first(); 40 41 if ($order === null) { 42 return; 43 } 44 45 $tokenRequest = new TokenRequest($projectId, (string) $user->user_id); 46 $tokenRequest 47 ->setSandboxMode($GLOBALS['cfg']['payments']['sandbox']) 48 ->setExternalPaymentId($order->getOrderNumber()) 49 ->setUserEmail($user->user_email) 50 ->setUserName($user->username) 51 ->setPurchase($order->getTotal(), 'USD') 52 ->setCustomParameters([ 53 'subtotal' => $order->getSubtotal(), 54 'shipping' => $order->shipping, 55 'order_id' => $order['order_id'], 56 ]); 57 58 $xsollaClient = XsollaClient::factory([ 59 'merchant_id' => $GLOBALS['cfg']['payments']['xsolla']['merchant_id'], 60 'api_key' => $GLOBALS['cfg']['payments']['xsolla']['api_key'], 61 ]); 62 63 // This will be used for XPayStationWidget options. 64 return [ 65 'access_token' => $xsollaClient->createPaymentUITokenFromRequest($tokenRequest), 66 'sandbox' => $GLOBALS['cfg']['payments']['sandbox'], 67 ]; 68 } 69 70 // Called by xsolla after payment is approved by user. 71 public function callback(HttpRequest $request) 72 { 73 $params = static::extractParams($request); 74 $signature = new XsollaSignature($request); 75 $processor = new XsollaPaymentProcessor($params, $signature); 76 77 try { 78 if ($processor->isSkipped()) { 79 return ['ok']; 80 } 81 82 $processor->run(); 83 } catch (OrderException $exception) { 84 log_error($exception); 85 86 return $this->errorResponse( 87 'A validation error occured while running the transaction', 88 'INVALID', 89 422 90 ); 91 } catch (InvalidSignatureException $exception) { 92 log_error($exception); 93 // xsolla expects INVALID_SIGNATURE 94 return $this->errorResponse('The signature is invalid.', 'INVALID_SIGNATURE', 422); 95 } catch (XsollaUserNotFoundException $exception) { 96 return $this->errorResponse('INVALID_USER', 'INVALID_USER', 404); 97 } catch (Exception $exception) { 98 log_error($exception); 99 100 // status code needs to be a 4xx code to make Xsolla an error to the user. 101 return $this->errorResponse('Something went wrong.', 'FATAL_ERROR', 422); 102 } 103 } 104 105 // After user has approved payment and redirected here by xsolla 106 public function completed() 107 { 108 $orderNumber = Request::input('foreignInvoice') ?? ''; 109 $order = OrderCheckout::for($orderNumber)->completeCheckout(); 110 111 return redirect(route('store.invoice.show', ['invoice' => $order->order_id, 'thanks' => 1])); 112 } 113 114 private function errorResponse(string $message, string $code, int $status) 115 { 116 return response()->json([ 117 'error' => [ 118 'code' => $code, 119 'message' => $message, 120 ], 121 ], $status); 122 } 123}