Initial commit

This commit is contained in:
root
2026-05-09 17:28:23 +02:00
commit 9d73f82529
5575 changed files with 281989 additions and 0 deletions
+152
View File
@@ -0,0 +1,152 @@
<?php
namespace App\Http\Controllers\Shop;
use App\Http\Controllers\Controller;
use App\Http\Requests\AccountTopupFormRequest;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Srmklive\PayPal\Services\PayPal;
use Srmklive\PayPal\Services\PayPal as PayPalClient;
use Symfony\Component\HttpFoundation\Response;
class PayPalController extends Controller
{
private const string STATUS_CANCELLED = 'CANCELLED';
private const string STATUS_COMPLETED = 'COMPLETED';
private ?PayPalClient $provider = null;
private function getProvider(): PayPalClient
{
if (! $this->provider instanceof PayPal) {
$this->provider = new PayPalClient;
$this->provider->setApiCredentials(config('habbo.paypal'));
$this->provider->getAccessToken();
}
return $this->provider;
}
public function process(AccountTopupFormRequest $request): Response|RedirectResponse
{
$amount = $request->integer('amount');
$orderData = [
'intent' => 'CAPTURE',
'application_context' => [
'return_url' => route('paypal.successful-transaction'),
'cancel_url' => route('paypal.cancelled-transaction'),
'brand_name' => setting('hotel_name'),
'landing_page' => 'BILLING',
'shipping_preference' => 'NO_SHIPPING',
'user_action' => 'CONTINUE',
],
'purchase_units' => [
0 => [
'amount' => [
'currency_code' => config('habbo.paypal.currency'),
'value' => (string) $amount,
],
],
],
];
$response = $this->getProvider()->createOrder($orderData);
if (isset($response['id']) === false) {
Log::error('Error creating order', ['response' => $response]);
return to_route('shop.index')->withErrors(
['message' => $response['message'] ?? __('Something went wrong')],
);
}
foreach ($response['links'] as $links) {
if ($links['rel'] === 'approve') {
$request->user()->transactions()->create([
'transaction_id' => $response['id'],
'amount' => 0,
]);
return redirect()->away($links['href']);
}
}
return to_route('shop.index')->withErrors(
['message' => $response['message'] ?? __('Something went wrong')],
);
}
public function successful(Request $request): Response
{
$request->validate([
'token' => 'required',
]);
$user = $request->user();
$transaction = $user->transactions()->where('transaction_id', $request['token'])->first();
if ($transaction === null) {
return to_route('shop.index')->withErrors(['message' => __('Something went wrong, please try again later')]);
}
$response = $this->getProvider()->capturePaymentOrder($request['token']);
$paymentDetails = $response['purchase_units'][0]['payments']['captures'][0];
if (! isset($response['status'], $paymentDetails)) {
Log::error('Invalid response from PayPal', ['response' => $response]);
return to_route('shop.index')->withErrors(['message' => __('Something went wrong, please try again later')]);
}
if (($response['status'] ?? null) === null) {
$details = $response['error']['details'][0];
$transaction->update([
'status' => $response['name'],
'description' => sprintf('%s - %s', $details['issue'], $details['description']),
'amount' => 0,
]);
return to_route('shop.index')->withErrors(['message' => __('Something went wrong, please check your paypal account to make sure nothing was deducted and try again')]);
}
$paymentDetails = $response['purchase_units'][0]['payments']['captures'][0];
$transaction->update([
'status' => $paymentDetails['status'],
'amount' => $paymentDetails['amount']['value'],
'currency' => $paymentDetails['amount']['currency_code'],
]);
if ($response['status'] !== self::STATUS_COMPLETED) {
return to_route('shop.index')->withErrors(
['message' => $response['message'] ?? __('Something went wrong')],
);
}
$user->increment('website_balance', $paymentDetails['amount']['value']);
return to_route('shop.index')->with('success', __('Transaction successful'));
}
public function cancelled(Request $request): Response
{
$request->validate([
'token' => 'required',
]);
$transaction = $request->user()->transactions()->where('transaction_id', $request['token'])->first();
if ($transaction !== null) {
$transaction->update([
'status' => self::STATUS_CANCELLED,
'description' => 'The user cancelled the transaction',
]);
}
return to_route('shop.index')->withErrors(
['message' => __('You have canceled the transaction')],
);
}
}
+89
View File
@@ -0,0 +1,89 @@
<?php
namespace App\Http\Controllers\Shop;
use App\Http\Controllers\Controller;
use App\Models\Shop\WebsiteShopArticle;
use App\Models\Shop\WebsiteShopCategory;
use App\Models\User;
use App\Services\PurchaseService;
use App\Services\RconService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class ShopController extends Controller
{
public function __construct(
private readonly RconService $rconService,
private readonly PurchaseService $purchaseService,
) {}
public function __invoke(?WebsiteShopCategory $category)
{
$query = WebsiteShopArticle::query()->orderBy('position');
if ($category && $category->exists) {
$query = $category->articles()->orderBy('position');
}
return view('shop.shop', [
'articles' => $query->with(['rank:id,rank_name', 'features'])->get(),
'categories' => WebsiteShopCategory::whereHas('articles')->get(),
]);
}
public function purchase(WebsiteShopArticle $package, Request $request): Response
{
/** @var User $currentUser */
$currentUser = Auth::user();
$recipient = null;
if ($request->has('receiver')) {
if (! $package->is_giftable) {
return to_route('shop.index')->withErrors(
['message' => __('This package is not giftable')],
);
}
$recipient = User::where('username', $request->input('receiver'))->first();
if (! $recipient) {
return to_route('shop.index')->withErrors(
['message' => __('Recipient not found')],
);
}
}
$user = $recipient ?? $currentUser;
if ($package->give_rank && $user->rank >= $package->give_rank) {
$message = __('You are already this or a higher rank');
if ($recipient && $user->username !== $currentUser->username) {
$message = __('The recipient is already this or a higher rank');
}
return to_route('shop.index')->withErrors(
['message' => $message],
);
}
if (! $this->rconService->isConnected && (int) $user->online === 1) {
return to_route('shop.index')->withErrors(
['message' => __('Please logout before purchasing a package')],
);
}
if ($currentUser->website_balance < $package->price()) {
return to_route('shop.index')->withErrors(
['message' => __('You need to top-up your account with another $:amount to purchase this package', ['amount' => ($package->price() - $currentUser->website_balance)])],
);
}
$message = $this->purchaseService->processPurchase($currentUser, $package, $recipient);
return to_route('shop.index')->with('success', $message);
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php
namespace App\Http\Controllers\Shop;
use App\Http\Controllers\Controller;
use App\Http\Requests\ShopVoucherFormRequest;
use App\Models\Shop\WebsiteShopVoucher;
class ShopVoucherController extends Controller
{
public function __invoke(ShopVoucherFormRequest $request)
{
$user = $request->user();
$voucher = WebsiteShopVoucher::where('code', $request->string('code'))->first();
if (is_null($voucher) || ($voucher->expires_at && $voucher->expires_at->lte(now()))) {
return redirect()->back()->withErrors([
'message' => __('No active voucher with the given code was found'),
]);
}
if ($user->usedShopVouchers()->where('voucher_id', $voucher->id)->exists()) {
return redirect()->back()->withErrors([
'message' => __('You can only use each shop voucher once'),
]);
}
$user->usedShopVouchers()->create([
'voucher_id' => $voucher->id,
]);
$user->increment('website_balance', $voucher->amount);
$voucher->increment('use_count');
if ($voucher->max_uses && $voucher->use_count >= $voucher->max_uses) {
$voucher->update([
'expires_at' => now(),
]);
}
return redirect()->back()->with('success', __('Your balance has been increased by $:amount', ['amount' => $voucher->amount]));
}
}