Files
BetiX/bootstrap/app.php
Dolo 0280278978
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled
Initialer Laravel Commit für BetiX
2026-04-04 18:01:50 +02:00

121 lines
5.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
use App\Http\Middleware\HandleAppearance;
use App\Http\Middleware\HandleInertiaRequests;
use App\Http\Middleware\SetLocale;
use App\Http\Middleware\CheckBanned;
use App\Http\Middleware\DetectCiphertextInJson;
use App\Http\Middleware\GeoBlockMiddleware;
use App\Http\Middleware\MaintenanceModeMiddleware;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
then: function () {
// B2B operator routes — served at /operator/* (no /api prefix)
\Illuminate\Support\Facades\Route::middleware(['throttle:60,1'])
->prefix('operator')
->group(base_path('routes/operator.php'));
},
)
->withSchedule(function (\Illuminate\Console\Scheduling\Schedule $schedule): void {
// Expire old user bonuses every hour
$schedule->call(function () {
app(\App\Services\BonusService::class)->expireBonuses();
})->hourly()->name('bonus:expire')->withoutOverlapping();
// Recalculate VIP levels based on total wager runs daily at 03:00
$schedule->call(function () {
$thresholds = [5 => 10000, 4 => 2000, 3 => 500, 2 => 100, 1 => 0];
\App\Models\User::chunk(200, function ($users) use ($thresholds) {
foreach ($users as $user) {
$totalWager = \App\Models\GameBet::where('user_id', $user->id)->sum('wager_amount');
$newLevel = 1;
foreach ($thresholds as $level => $min) {
if ($totalWager >= $min) { $newLevel = $level; break; }
}
if ($user->vip_level !== $newLevel) {
$user->forceFill(['vip_level' => $newLevel])->save();
}
}
});
})->dailyAt('03:00')->name('vip:recalculate')->withoutOverlapping();
// Flag / notify inactive users (no login for 90 days) runs weekly
$schedule->call(function () {
$cutoff = now()->subDays(90);
\App\Models\User::where('last_login_at', '<', $cutoff)
->where('is_banned', false)
->chunk(100, function ($users) {
foreach ($users as $user) {
\Illuminate\Support\Facades\Log::info('Inactive user flagged', [
'user_id' => $user->id,
'last_login_at' => $user->last_login_at,
]);
}
});
})->weekly()->name('users:cleanup-inactive')->withoutOverlapping();
})
->withMiddleware(function (Middleware $middleware): void {
$middleware->encryptCookies(except: ['appearance', 'sidebar_state', 'XSRF-TOKEN']);
$middleware->validateCsrfTokens(except: [
'api/webhooks/nowpayments',
'api/betix/*',
'wallet/deposits',
'locale',
'api/wallet/vault/*',
'api/wallet/vault',
// Operator B2B API — authenticated via license key, not CSRF
'operator/*',
]);
$middleware->web(append: [
HandleAppearance::class,
SetLocale::class,
HandleInertiaRequests::class,
AddLinkHeadersForPreloadedAssets::class,
CheckBanned::class,
DetectCiphertextInJson::class,
GeoBlockMiddleware::class,
MaintenanceModeMiddleware::class,
]);
// Route middleware aliases
$middleware->alias([
'restrict' => \App\Http\Middleware\EnforceRestriction::class,
'license.key' => \App\Http\Middleware\ValidateLicenseKey::class,
]);
})
->withExceptions(function (Exceptions $exceptions): void {
$exceptions->render(function (\Illuminate\Validation\ValidationException $e, $request) {
if ($request->is('api/*')) {
return response()->json([
'message' => 'The given data was invalid.',
'errors' => $e->errors(),
], 422);
}
});
$exceptions->render(function (\Illuminate\Auth\AuthenticationException $e, $request) {
if ($request->is('api/*')) {
return response()->json(['message' => 'Unauthenticated.'], 401);
}
});
$exceptions->render(function (\Symfony\Component\HttpKernel\Exception\HttpException $e, $request) {
if ($request->is('api/*')) {
return response()->json([
'message' => $e->getMessage() ?: 'An error occurred.',
'status' => $e->getStatusCode(),
], $e->getStatusCode());
}
});
})->create();